#!/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. """Fork-chain wallet transactions use locktime 0. The fork chain shares its transaction set with the parent (spamchain) chain, but the two chains diverge in height after the fork point. A height-based locktime (the wallet's fee-sniping mitigation) from the taller fork chain would make a transaction non-final - and thus mempool-rejected - on the shorter parent chain, breaking cross-chain propagation. The fork-chain wallet therefore skips the fee-sniping locktime: every wallet transaction is final (locktime 0) and valid on both diverging chains. Other chains keep the standard behavior. """ from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import LimenkaTestFramework class ForkWalletLocktimeTest(LimenkaTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.chain = 'limenka' self.extra_args = [[ '-forkactivationheight=50', '-forkdelaysteps=1024', '-forkmineondemand', '-forkstandalone', '-fallbackfee=0.0002', '-addresstype=bech32', ]] 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: n.createwallet(wallet_name=wallet_name, descriptors=True, load_on_startup=True) import hashlib from test_framework.address import byte_to_base58 from test_framework.descriptors import descsum_create from test_framework.key import ECKey key = ECKey() key.set(hashlib.sha256(b'fork-wallet-locktime').digest(), 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": 1231006506, "active": False, "internal": False, }]) assert all(r['success'] for r in import_res) def run_test(self): node = self.nodes[0] for i in range(COINBASE_MATURITY + 10): node.setmocktime(1700000000 + i * 600) self.generatetoaddress(node, 1, node.getnewaddress(), sync_fun=self.no_op) # A fork-chain wallet tx must be final (locktime 0), so it is valid # on the shorter parent chain too. txid = node.sendtoaddress(node.getnewaddress(), 1) raw = node.getrawtransaction(txid) decoded = node.decoderawtransaction(raw) assert decoded['locktime'] == 0, decoded['locktime'] self.log.info("fork wallet tx locktime == 0 (final on both chains)") if __name__ == '__main__': ForkWalletLocktimeTest(__file__).main()