Repository: bitcoin/bitcoin
File: test/functional/mempool_ephemeral_dust.py (Python)

Code before:
        self.noban_tx_relay = True

    def add_output_to_create_multi_result(self, result, output_value=0):
        """ Add output without changing absolute tx fee
        """
        assert len(result["tx"].vout) > 0
        assert result["tx"].vout[0].nValue >= output_value
        result["tx"].vout.append(CTxOut(output_value, result["tx"].vout[0].scriptPubKey))
        # Take value from first output
        result["tx"].vout[0].nValue -= output_value
        result["new_utxos"][0]["value"] = Decimal(result["tx"].vout[0].nValue) / COIN
        new_txid = result["tx"].rehash()
        result["txid"]  = new_txid
        result["wtxid"] = result["tx"].getwtxid()
        result["hex"] = result["tx"].serialize().hex()
        for new_utxo in result["new_utxos"]:
            new_utxo["txid"] = new_txid
            new_utxo["wtxid"] = result["tx"].getwtxid()

        result["new_utxos"].append({"txid": new_txid, "vout": len(result["tx"].vout) - 1, "value": Decimal(output_value) / COIN, "height": 0, "coinbase": False, "confirmations": 0})

    def run_test(self):

        node = self.nodes[0]
        self.wallet = MiniWallet(node)

        self.test_normal_dust()
        self.test_sponsor_cycle()
        self.test_node_restart()
        self.test_fee_having_parent()
        self.test_multidust()
        self.test_nonzero_dust()
        self.test_non_truc()
        self.test_unspent_ephemeral()
        self.test_reorgs()
        self.test_no_minrelay_fee()

    def test_normal_dust(self):
        self.log.info("Create 0-value dusty output, show that it works inside truc when spent in package")

        assert_equal(self.nodes[0].getrawmempool(), [])

        dusty_tx = self.wallet.create_self_transfer_multi(fee_per_output=0, version=3)
        self.add_output_to_create_multi_result(dusty_tx)

        sweep_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=dusty_tx["new_utxos"], version=3)

        # Test doesn't work because lack of package feerates
        test_res = self.nodes[0].testmempoolaccept([dusty_tx["hex"], sweep_tx["hex"]])
        assert not test_res[0]["allowed"]
        assert_equal(test_res[0]["reject-reason"], "min relay fee not met")

Review comment (suggestion):
```
fee_per_output=dust_tx_fee
```

Since technically it's the fee per output, let's call it `dust_tx_fee_per_output`? Otherwise reading the function signatures gives an impression that `dust_tx_fee` is for the whole tx.

Code after:
        self.noban_tx_relay = True

    def add_output_to_create_multi_result(self, result, output_value=0):
        """ Add output without changing absolute tx fee
        """
        assert len(result["tx"].vout) > 0
        assert result["tx"].vout[0].nValue >= output_value
        result["tx"].vout.append(CTxOut(output_value, result["tx"].vout[0].scriptPubKey))
        # Take value from first output
        result["tx"].vout[0].nValue -= output_value
        result["new_utxos"][0]["value"] = Decimal(result["tx"].vout[0].nValue) / COIN
        new_txid = result["tx"].rehash()
        result["txid"]  = new_txid
        result["wtxid"] = result["tx"].getwtxid()
        result["hex"] = result["tx"].serialize().hex()
        for new_utxo in result["new_utxos"]:
            new_utxo["txid"] = new_txid
            new_utxo["wtxid"] = result["tx"].getwtxid()

        result["new_utxos"].append({"txid": new_txid, "vout": len(result["tx"].vout) - 1, "value": Decimal(output_value) / COIN, "height": 0, "coinbase": False, "confirmations": 0})

    def create_ephemeral_dust_package(self, *, tx_version, dust_tx_fee=0, dust_value=0, num_dust_outputs=1, extra_sponsors=None):
        """Creates a 1P1C package containing ephemeral dust. By default, the parent transaction
           is zero-fee and creates a single zero-value dust output, and all of its outputs are
           spent by the child."""
        dusty_tx = self.wallet.create_self_transfer_multi(fee_per_output=dust_tx_fee, version=tx_version)
        for _ in range(num_dust_outputs):
            self.add_output_to_create_multi_result(dusty_tx, dust_value)

        extra_sponsors = extra_sponsors or []
        sweep_tx = self.wallet.create_self_transfer_multi(
            utxos_to_spend=dusty_tx["new_utxos"] + extra_sponsors,
            version=tx_version,
        )

        return dusty_tx, sweep_tx

    def run_test(self):

        node = self.nodes[0]
        self.wallet = MiniWallet(node)

        self.test_normal_dust()
        self.test_sponsor_cycle()
        self.test_node_restart()
        self.test_fee_having_parent()
        self.test_multidust()
        self.test_nonzero_dust()
        self.test_non_truc()
        self.test_unspent_ephemeral()
        self.test_reorgs()