Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1#!/usr/bin/env python32# Copyright (c) 2022-present The Bitcoin Core developers3# Distributed under the MIT software license, see the accompanying4# file COPYING or http://www.opensource.org/licenses/mit-license.php.5"""Test dust limit mempool policy (`-dustrelayfee` parameter)"""6from decimal import Decimal8from test_framework.messages import (9COIN,10CTxOut,11)12from test_framework.script import (13CScript,14OP_RETURN,15OP_TRUE,16)17from test_framework.script_util import (18key_to_p2pk_script,19key_to_p2pkh_script,20key_to_p2wpkh_script,21keys_to_multisig_script,22output_key_to_p2tr_script,23program_to_witness_script,24script_to_p2sh_script,25script_to_p2wsh_script,26)27from test_framework.test_framework import BitcoinTestFramework28from test_framework.test_node import TestNode29from test_framework.util import (30assert_equal,31get_fee,32)33from test_framework.wallet import MiniWallet34from test_framework.wallet_util import generate_keypair37DUST_RELAY_TX_FEE = 3000 # default setting [sat/kvB]40class DustRelayFeeTest(BitcoinTestFramework):41def set_test_params(self):42self.num_nodes = 143self.extra_args = [['-permitbaremultisig']]45def test_dust_output(self, node: TestNode, dust_relay_fee: Decimal,46output_script: CScript, type_desc: str) -> None:47# determine dust threshold (see `GetDustThreshold`)48if output_script[0] == OP_RETURN:49dust_threshold = 050else:51tx_size = len(CTxOut(nValue=0, scriptPubKey=output_script).serialize())52tx_size += 67 if output_script.IsWitnessProgram() else 14853dust_threshold = int(get_fee(tx_size, dust_relay_fee) * COIN)54self.log.info(f"-> Test {type_desc} output (size {len(output_script)}, limit {dust_threshold})")56# amount right on the dust threshold should pass57tx = self.wallet.create_self_transfer()["tx"]58tx.vout.append(CTxOut(nValue=dust_threshold, scriptPubKey=output_script))59tx.vout[0].nValue -= dust_threshold # keep total output value constant60tx_good_hex = tx.serialize().hex()61res = node.testmempoolaccept([tx_good_hex])[0]62assert_equal(res['allowed'], True)64# amount just below the dust threshold should fail65if dust_threshold > 0:66tx.vout[1].nValue -= 167res = node.testmempoolaccept([tx.serialize().hex()])[0]68assert_equal(res['allowed'], False)69assert_equal(res['reject-reason'], 'dust')71# finally send the transaction to avoid running out of MiniWallet UTXOs72self.wallet.sendrawtransaction(from_node=node, tx_hex=tx_good_hex)74def test_dustrelay(self):75self.log.info("Test that small outputs are acceptable when dust relay rate is set to 0 that would otherwise trigger ephemeral dust rules")77self.restart_node(0, extra_args=["-dustrelayfee=0"])79assert_equal(self.nodes[0].getrawmempool(), [])81# Create two dust outputs. Transaction has zero fees. both dust outputs are unspent, and would have failed individual checks.82# The amount is 1 satoshi because create_self_transfer_multi disallows 0.83dusty_tx = self.wallet.create_self_transfer_multi(fee_per_output=1000, amount_per_output=1, num_outputs=2)84dust_txid = self.nodes[0].sendrawtransaction(hexstring=dusty_tx["hex"], maxfeerate=0)86assert_equal(self.nodes[0].getrawmempool(), [dust_txid])88# Spends one dust along with fee input, leave other dust unspent to check ephemeral dust checks aren't being enforced89sweep_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=[self.wallet.get_utxo(), dusty_tx["new_utxos"][0]])90sweep_txid = self.nodes[0].sendrawtransaction(sweep_tx["hex"])92mempool_entries = self.nodes[0].getrawmempool()93assert dust_txid in mempool_entries94assert sweep_txid in mempool_entries95assert_equal(len(mempool_entries), 2)97# Wipe extra arg to reset dust relay98self.restart_node(0, extra_args=[])100assert_equal(self.nodes[0].getrawmempool(), [])102def run_test(self):103self.wallet = MiniWallet(self.nodes[0])105self.test_dustrelay()107# prepare output scripts of each standard type108_, uncompressed_pubkey = generate_keypair(compressed=False)109_, pubkey = generate_keypair(compressed=True)111output_scripts = (112(key_to_p2pk_script(uncompressed_pubkey), "P2PK (uncompressed)"),113(key_to_p2pk_script(pubkey), "P2PK (compressed)"),114(key_to_p2pkh_script(pubkey), "P2PKH"),115(script_to_p2sh_script(CScript([OP_TRUE])), "P2SH"),116(key_to_p2wpkh_script(pubkey), "P2WPKH"),117(script_to_p2wsh_script(CScript([OP_TRUE])), "P2WSH"),118(output_key_to_p2tr_script(pubkey[1:]), "P2TR"),119# witness programs for segwitv2+ can be between 2 and 40 bytes120(program_to_witness_script(2, b'\x66' * 2), "P2?? (future witness version 2)"),121(program_to_witness_script(16, b'\x77' * 40), "P2?? (future witness version 16)"),122# largest possible output script considered standard123(keys_to_multisig_script([uncompressed_pubkey]*3), "bare multisig (m-of-3)"),124(CScript([OP_RETURN, b'superimportanthash']), "null data (OP_RETURN)"),125)127# test default (no parameter), disabled (=0) and a bunch of arbitrary dust fee rates [sat/kvB]128for dustfee_sat_kvb in (DUST_RELAY_TX_FEE, 0, 1, 66, 500, 1337, 12345, 21212, 333333):129dustfee_btc_kvb = dustfee_sat_kvb / Decimal(COIN)130if dustfee_sat_kvb == DUST_RELAY_TX_FEE:131self.log.info(f"Test default dust limit setting ({dustfee_sat_kvb} sat/kvB)...")132else:133dust_parameter = f"-dustrelayfee={dustfee_btc_kvb:.8f}"134self.log.info(f"Test dust limit setting {dust_parameter} ({dustfee_sat_kvb} sat/kvB)...")135self.restart_node(0, extra_args=[dust_parameter, "-permitbaremultisig"])137for output_script, description in output_scripts:138self.test_dust_output(self.nodes[0], dustfee_btc_kvb, output_script, description)139self.generate(self.nodes[0], 1)142if __name__ == '__main__':143DustRelayFeeTest(__file__).main()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.