Changeset View
Changeset View
Standalone View
Standalone View
test/functional/mining_cpfp_depth_1.py
- This file was added.
Property | Old Value | New Value |
---|---|---|
File Mode | null | 100755 |
#!/usr/bin/env python3 | |||||
# Copyright (c) 2019 The Bitcoin developers | |||||
# Distributed under the MIT software license, see the accompanying | |||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | |||||
""" | |||||
Child-Pays-for-Parent: Depth 1. | |||||
A child transaction with a sufficiently high fee can lead to | |||||
the inclusion of its parent transaction into a block; even if | |||||
the block is full and the parent has a fee which is lower than | |||||
that of all other transactions in the mempool. | |||||
""" | |||||
from test_framework.blocktools import ( | |||||
create_confirmed_utxos, | |||||
) | |||||
from test_framework.test_framework import BitcoinTestFramework | |||||
from test_framework.util import ( | |||||
assert_equal, | |||||
assert_less_than, | |||||
) | |||||
class ChildPaysForParentTest(BitcoinTestFramework): | |||||
def set_test_params(self): | |||||
""" | |||||
Sets -blockmaxsize such that we can create a full block | |||||
with approximately 20 transactions during the test. The | |||||
exacty amount does not matter; only that it is full. | |||||
""" | |||||
self.setup_clean_chain = True | |||||
self.num_nodes = 1 | |||||
self.block_max_tx_count = 20 | |||||
self.block_max_size = 200 + 192 * self.block_max_tx_count | |||||
self.extra_args = [[ | |||||
"-blockprioritypercentage=0", | |||||
"-blockmaxsize={}".format(self.block_max_size) | |||||
]] | |||||
def run_test(self): | |||||
""" | |||||
Broadcasts more transactions that can fit into a block, and then | |||||
generates a block. The set of transactions includes many medium-fee | |||||
transactions, as well as a low-fee transaction [parent tx] and a | |||||
high-fee dependent transaction [child tx]. CPFP guarantees that | |||||
parent tx will be included in the block, even though all other | |||||
transactions in the mempool have a significantly higher fee. | |||||
""" | |||||
node = self.nodes[0] | |||||
# Define fees. | |||||
network_info = node.getnetworkinfo() | |||||
relay_fee = network_info['relayfee'] | |||||
fee_parent = relay_fee | |||||
fee_child = 10 * relay_fee | |||||
fee_others = 5 * relay_fee | |||||
# Create confirmed utxos. We need enough of them such that we can | |||||
# create sufficient independent transactions to saturate a block. | |||||
utxos = create_confirmed_utxos(node, 2 * self.block_max_tx_count) | |||||
utxo_parent = utxos[0] | |||||
utxos_other = utxos[1:] | |||||
# Create the first independent transaction. [parent tx] | |||||
node.settxfee(fee_parent) | |||||
output_address_parent = node.getnewaddress() | |||||
inputs_parent = [ | |||||
{"txid": utxo_parent["txid"], "vout": utxo_parent["vout"]}] | |||||
outputs_parent = {output_address_parent: 0.02} | |||||
tx_parent = node.createrawtransaction(inputs_parent, outputs_parent) | |||||
tx_parent = node.fundrawtransaction(tx_parent) | |||||
tx_parent = node.signrawtransaction(tx_parent['hex']) | |||||
txid_parent = node.sendrawtransaction(tx_parent['hex']) | |||||
self.log.debug("Broadcasted parent tx: {}.".format(txid_parent)) | |||||
deadalnix: You need to check that that transaction is rejected. If not then you test nothing. | |||||
# Create a transaction dependent on the first transaction. [child tx] | |||||
node.settxfee(fee_child) | |||||
output_address_child = node.getnewaddress() | |||||
inputs_child = [{"txid": txid_parent, "vout": 0}] | |||||
outputs_child = {output_address_child: 0.01} | |||||
tx_child = node.createrawtransaction(inputs_child, outputs_child) | |||||
tx_child = node.fundrawtransaction(tx_child) | |||||
tx_child = node.signrawtransaction(tx_child['hex']) | |||||
txid_child = node.sendrawtransaction(tx_child['hex']) | |||||
self.log.debug("Broadcasted child tx: {}.".format(txid_child)) | |||||
deadalnixUnsubmitted Not Done Inline ActionsYou need to check that the nose will request the parent from you. This means you need to connect to the node via a test node and not via the RPC. deadalnix: You need to check that the nose will request the parent from you. This means you need to… | |||||
# Create more independent transactions. [other txs] | |||||
for utxo_other in utxos_other: | |||||
node.settxfee(fee_others) | |||||
output_address_other = node.getnewaddress() | |||||
inputs_other = [ | |||||
{"txid": utxo_other["txid"], "vout": utxo_other["vout"]}] | |||||
outputs_other = {output_address_other: 0.01} | |||||
tx_other = node.createrawtransaction(inputs_other, outputs_other) | |||||
tx_other = node.fundrawtransaction(tx_other) | |||||
tx_other = node.signrawtransaction(tx_other['hex']) | |||||
txid_other = node.sendrawtransaction(tx_other['hex']) | |||||
self.log.debug("Broadcasted other tx: {}.".format(txid_other)) | |||||
# Generate block. | |||||
block_hashes = node.generate(nblocks=1) | |||||
block_hash = block_hashes[0] | |||||
block = node.getblock(block_hash) | |||||
block_txids = block["tx"] | |||||
self.log.debug("Generated block: {}.".format(block_hash)) | |||||
# Make sure that the block *does not* contain all broadcasted | |||||
# txs; ie, some of them where left out. | |||||
confirmed_transactions = len(block_txids) | |||||
broadcasted_transactions = 1 + 1 + len(utxos_other) | |||||
assert_less_than(confirmed_transactions, broadcasted_transactions) | |||||
# Make sure that the block contains both the parent and child | |||||
# txs, even though the block is full and the parent tx has a | |||||
# lower fee than all the other transactions. | |||||
assert_equal(txid_parent in block_txids, True) | |||||
assert_equal(txid_child in block_txids, True) | |||||
if __name__ == '__main__': | |||||
ChildPaysForParentTest().main() |
You need to check that that transaction is rejected. If not then you test nothing.