git / moonbite-core / test/functional/mweb_duplicate_pegin.py · raw

#!/usr/bin/env python3# Copyright (c) 2026 The Litecoin Core developers# Distributed under the MIT software license, see the accompanying# file COPYING or http://www.opensource.org/licenses/mit-license.php."""Test duplicate canonical pegins for the same MWEB kernel."""from test_framework.blocktools import (    NORMAL_GBT_REQUEST_PARAMS,    add_witness_commitment,    create_coinbase,)from test_framework.ltc_util import create_hogex, setup_mweb_chainfrom test_framework.messages import (    COIN,    CBlock,    COutPoint,    CTransaction,    CTxIn,    CTxOut,    FromHex,    MWEBBlock,)from test_framework.script import CScriptfrom test_framework.test_framework import BitcoinTestFrameworkfrom test_framework.util import assert_equalMWEB_PEGIN_OPCODE = 0x59class MWEBDuplicatePeginTest(BitcoinTestFramework):    def set_test_params(self):        self.num_nodes = 1        self.setup_clean_chain = True        self.supports_cli = False    def skip_test_if_missing_module(self):        self.skip_if_no_wallet()    @staticmethod    def is_mweb_pegin_script(script):        script = bytes(script)        return len(script) == 34 and script[0] == MWEB_PEGIN_OPCODE and script[1] == 32    def get_template_parts(self, node, pegin_txid):        gbt = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)        assert "mweb" in gbt        template_txs = []        for entry in gbt["transactions"]:            tx = FromHex(CTransaction(), entry["data"])            tx.rehash()            template_txs.append(tx)        pegin_tx = next(tx for tx in template_txs if tx.hash == pegin_txid)        hogex_tx = next(tx for tx in template_txs if tx.hogex)        pegin_outputs = [            (n, txout) for n, txout in enumerate(pegin_tx.vout)            if self.is_mweb_pegin_script(txout.scriptPubKey)        ]        assert_equal(len(pegin_outputs), 1)        return (            gbt,            FromHex(MWEBBlock(), gbt["mweb"]),            hogex_tx.vout[0].nValue,            pegin_outputs[0][1].nValue,            pegin_outputs[0][1].scriptPubKey,        )    def create_signed_duplicate_pegin_tx(self, wallet, pegin_amount, pegin_script, duplicate_amount):        spend_amount = pegin_amount + duplicate_amount        fee = 10_000        spend_utxo = next(            utxo for utxo in wallet.listunspent()            if utxo["spendable"]            and not utxo.get("address", "").startswith("tmweb")            and utxo["confirmations"] > 100            and int(utxo["amount"] * COIN) > spend_amount + fee        )        change_script = CScript(bytes.fromhex(            wallet.getaddressinfo(wallet.getrawchangeaddress())["scriptPubKey"]        ))        input_amount = int(spend_utxo["amount"] * COIN)        tx = CTransaction()        tx.vin = [CTxIn(COutPoint(int(spend_utxo["txid"], 16), spend_utxo["vout"]))]        tx.vout = [            CTxOut(pegin_amount, pegin_script),            CTxOut(duplicate_amount, pegin_script),            CTxOut(input_amount - spend_amount - fee, change_script),        ]        tx.rehash()        signed = wallet.signrawtransactionwithwallet(tx.serialize().hex())        assert signed["complete"]        signed_tx = FromHex(CTransaction(), signed["hex"])        signed_tx.rehash()        return signed_tx    def create_duplicate_pegin_block(self, node, gbt, mweb_block, hogex_amount, pegin_tx):        hogex_tx = create_hogex(node, mweb_block.header.hash, amount=hogex_amount)        hogex_tx.vin.extend([            CTxIn(COutPoint(pegin_tx.sha256, 0)),            CTxIn(COutPoint(pegin_tx.sha256, 1)),        ])        hogex_tx.rehash()        coinbase_tx = create_coinbase(height=int(gbt["height"]))        block = CBlock()        block.nVersion = gbt["version"]        block.hashPrevBlock = int(gbt["previousblockhash"], 16)        block.nTime = gbt["curtime"]        block.nBits = int(gbt["bits"], 16)        block.nNonce = 0        block.vtx = [coinbase_tx, pegin_tx, hogex_tx]        block.mweb_block = mweb_block        block.hashMerkleRoot = block.calc_merkle_root()        if not pegin_tx.wit.is_null():            add_witness_commitment(block)        return block    def assert_template_result(self, node, block, expected):        assert_equal(node.getblocktemplate({            "data": block.serialize().hex(),            "mode": "proposal",            "rules": ["mweb", "segwit"],        }), expected)    def run_test(self):        node = self.nodes[0]        miner = node.get_wallet_rpc(self.default_wallet_name)        self.log.info("Activate MWEB")        setup_mweb_chain(node)        self.log.info("Create an LTC-only pegin source with one small confirmed coin")        node.createwallet(wallet_name="pegin_source")        pegin_source = node.get_wallet_rpc("pegin_source")        miner.sendtoaddress(pegin_source.getnewaddress(address_type="legacy"), 3)        node.generatetoaddress(1, miner.getnewaddress())        self.log.info("Build a template containing one valid pegin")        pegin_txid = pegin_source.sendtoaddress(            address=pegin_source.getnewaddress(address_type="mweb"),            amount=1,        )        gbt, mweb_block, hogex_amount, pegin_amount, pegin_script = self.get_template_parts(node, pegin_txid)        self.log.info("A positive-value duplicate pegin is rejected by MWEB pegin matching")        positive_duplicate_tx = self.create_signed_duplicate_pegin_tx(            miner,            pegin_amount,            pegin_script,            duplicate_amount=pegin_amount,        )        positive_duplicate_block = self.create_duplicate_pegin_block(            node,            gbt,            mweb_block,            hogex_amount,            positive_duplicate_tx,        )        self.assert_template_result(node, positive_duplicate_block, "bad-blk-mweb")        self.log.info("A zero-value duplicate pegin to the same kernel should be rejected")        zero_duplicate_tx = self.create_signed_duplicate_pegin_tx(            miner,            pegin_amount,            pegin_script,            duplicate_amount=0,        )        zero_duplicate_block = self.create_duplicate_pegin_block(            node,            gbt,            mweb_block,            hogex_amount,            zero_duplicate_tx,        )        self.assert_template_result(node, zero_duplicate_block, "bad-blk-mweb")if __name__ == "__main__":    MWEBDuplicatePeginTest().main()