2018-12-18 12:00:46 -08:00
|
|
|
#!/usr/bin/env python
|
2017-01-11 04:25:19 -08:00
|
|
|
# Copyright (c) 2017 The Zcash developers
|
|
|
|
# Distributed under the MIT software license, see the accompanying
|
2019-07-18 07:16:09 -07:00
|
|
|
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
2017-01-11 04:25:19 -08:00
|
|
|
|
2018-12-18 12:00:46 -08:00
|
|
|
import sys; assert sys.version_info < (3,), ur"This script does not run under Python 3. Please use Python 2.7.x."
|
|
|
|
|
2017-01-11 04:25:19 -08:00
|
|
|
from test_framework.test_framework import BitcoinTestFramework
|
2017-06-20 13:09:33 -07:00
|
|
|
from test_framework.util import assert_equal, initialize_chain_clean, \
|
|
|
|
start_node, connect_nodes
|
2017-01-11 04:25:19 -08:00
|
|
|
from test_framework.mininode import COIN
|
2017-06-20 13:09:33 -07:00
|
|
|
|
2017-04-14 17:31:35 -07:00
|
|
|
import time
|
|
|
|
|
2017-01-11 04:25:19 -08:00
|
|
|
|
|
|
|
class PrioritiseTransactionTest (BitcoinTestFramework):
|
|
|
|
|
|
|
|
def setup_chain(self):
|
|
|
|
print("Initializing test directory "+self.options.tmpdir)
|
|
|
|
initialize_chain_clean(self.options.tmpdir, 4)
|
|
|
|
|
|
|
|
def setup_network(self, split=False):
|
|
|
|
self.nodes = []
|
|
|
|
# Start nodes with tiny block size of 11kb
|
|
|
|
self.nodes.append(start_node(0, self.options.tmpdir, ["-blockprioritysize=7000", "-blockmaxsize=11000", "-maxorphantx=1000", "-relaypriority=true", "-printpriority=1"]))
|
|
|
|
self.nodes.append(start_node(1, self.options.tmpdir, ["-blockprioritysize=7000", "-blockmaxsize=11000", "-maxorphantx=1000", "-relaypriority=true", "-printpriority=1"]))
|
|
|
|
connect_nodes(self.nodes[1], 0)
|
|
|
|
self.is_network_split=False
|
|
|
|
self.sync_all()
|
|
|
|
|
|
|
|
def run_test (self):
|
|
|
|
# tx priority is calculated: priority = sum(input_value_in_base_units * input_age)/size_in_bytes
|
|
|
|
|
|
|
|
print "Mining 11kb blocks..."
|
|
|
|
self.nodes[0].generate(501)
|
|
|
|
|
|
|
|
base_fee = self.nodes[0].getnetworkinfo()['relayfee']
|
|
|
|
|
|
|
|
# 11 kb blocks will only hold about 50 txs, so this will fill mempool with older txs
|
|
|
|
taddr = self.nodes[1].getnewaddress()
|
2017-02-27 14:11:09 -08:00
|
|
|
for _ in range(900):
|
2017-01-11 04:25:19 -08:00
|
|
|
self.nodes[0].sendtoaddress(taddr, 0.1)
|
|
|
|
self.nodes[0].generate(1)
|
|
|
|
self.sync_all()
|
|
|
|
|
|
|
|
# Create tx of lower value to be prioritized on node 0
|
2017-04-14 17:31:35 -07:00
|
|
|
# Older transactions get mined first, so this lower value, newer tx is unlikely to be mined without prioritisation
|
2017-01-11 04:25:19 -08:00
|
|
|
priority_tx_0 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)
|
|
|
|
|
|
|
|
# Check that priority_tx_0 is not in block_template() prior to prioritisation
|
|
|
|
block_template = self.nodes[0].getblocktemplate()
|
2017-02-27 14:11:09 -08:00
|
|
|
in_block_template = False
|
2017-01-11 04:25:19 -08:00
|
|
|
for tx in block_template['transactions']:
|
|
|
|
if tx['hash'] == priority_tx_0:
|
2017-02-27 14:11:09 -08:00
|
|
|
in_block_template = True
|
2017-01-11 04:25:19 -08:00
|
|
|
break
|
2017-02-27 14:11:09 -08:00
|
|
|
assert_equal(in_block_template, False)
|
2017-01-11 04:25:19 -08:00
|
|
|
|
2017-04-14 17:31:35 -07:00
|
|
|
priority_success = self.nodes[0].prioritisetransaction(priority_tx_0, 1000, int(3 * base_fee * COIN))
|
|
|
|
assert(priority_success)
|
2017-01-11 04:25:19 -08:00
|
|
|
|
2017-03-22 22:57:13 -07:00
|
|
|
# Check that prioritized transaction is not in getblocktemplate()
|
|
|
|
# (not updated because no new txns)
|
|
|
|
in_block_template = False
|
|
|
|
block_template = self.nodes[0].getblocktemplate()
|
|
|
|
for tx in block_template['transactions']:
|
|
|
|
if tx['hash'] == priority_tx_0:
|
|
|
|
in_block_template = True
|
|
|
|
break
|
|
|
|
assert_equal(in_block_template, False)
|
|
|
|
|
2017-04-14 17:31:35 -07:00
|
|
|
# Sending a new transaction will make getblocktemplate refresh within 10s
|
2017-03-22 22:57:13 -07:00
|
|
|
self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)
|
|
|
|
|
|
|
|
# Check that prioritized transaction is not in getblocktemplate()
|
|
|
|
# (too soon)
|
2017-02-27 14:11:09 -08:00
|
|
|
in_block_template = False
|
2017-01-11 04:25:19 -08:00
|
|
|
block_template = self.nodes[0].getblocktemplate()
|
|
|
|
for tx in block_template['transactions']:
|
|
|
|
if tx['hash'] == priority_tx_0:
|
2017-02-27 14:11:09 -08:00
|
|
|
in_block_template = True
|
2017-01-11 04:25:19 -08:00
|
|
|
break
|
2017-02-27 14:11:09 -08:00
|
|
|
assert_equal(in_block_template, False)
|
2017-01-11 04:25:19 -08:00
|
|
|
|
2017-03-22 22:57:13 -07:00
|
|
|
# Check that prioritized transaction is in getblocktemplate()
|
2017-04-14 17:31:35 -07:00
|
|
|
# getblocktemplate() will refresh after 1 min, or after 10 sec if new transaction is added to mempool
|
|
|
|
# Mempool is probed every 10 seconds. We'll give getblocktemplate() a maximum of 30 seconds to refresh
|
2017-03-22 22:57:13 -07:00
|
|
|
block_template = self.nodes[0].getblocktemplate()
|
2017-04-14 17:31:35 -07:00
|
|
|
start = time.time();
|
|
|
|
in_block_template = False
|
|
|
|
while in_block_template == False:
|
|
|
|
for tx in block_template['transactions']:
|
|
|
|
if tx['hash'] == priority_tx_0:
|
|
|
|
in_block_template = True
|
|
|
|
break
|
|
|
|
if time.time() - start > 30:
|
|
|
|
raise AssertionError("Test timed out because prioritised transaction was not returned by getblocktemplate within 30 seconds.")
|
2017-06-20 13:09:33 -07:00
|
|
|
time.sleep(1)
|
2017-04-14 17:31:35 -07:00
|
|
|
block_template = self.nodes[0].getblocktemplate()
|
|
|
|
|
|
|
|
assert(in_block_template)
|
2017-03-22 22:57:13 -07:00
|
|
|
|
2017-01-11 04:25:19 -08:00
|
|
|
# Node 1 doesn't get the next block, so this *shouldn't* be mined despite being prioritized on node 1
|
|
|
|
priority_tx_1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.1)
|
|
|
|
self.nodes[1].prioritisetransaction(priority_tx_1, 1000, int(3 * base_fee * COIN))
|
|
|
|
|
|
|
|
# Mine block on node 0
|
|
|
|
blk_hash = self.nodes[0].generate(1)
|
|
|
|
block = self.nodes[0].getblock(blk_hash[0])
|
|
|
|
self.sync_all()
|
|
|
|
|
|
|
|
# Check that priority_tx_0 was mined
|
|
|
|
mempool = self.nodes[0].getrawmempool()
|
|
|
|
assert_equal(priority_tx_0 in block['tx'], True)
|
|
|
|
assert_equal(priority_tx_0 in mempool, False)
|
|
|
|
|
|
|
|
# Check that priority_tx_1 was not mined
|
|
|
|
assert_equal(priority_tx_1 in mempool, True)
|
|
|
|
assert_equal(priority_tx_1 in block['tx'], False)
|
|
|
|
|
|
|
|
# Mine a block on node 1 and sync
|
|
|
|
blk_hash_1 = self.nodes[1].generate(1)
|
|
|
|
block_1 = self.nodes[1].getblock(blk_hash_1[0])
|
|
|
|
self.sync_all()
|
|
|
|
|
|
|
|
# Check to see if priority_tx_1 is now mined
|
|
|
|
mempool_1 = self.nodes[1].getrawmempool()
|
|
|
|
assert_equal(priority_tx_1 in mempool_1, False)
|
|
|
|
assert_equal(priority_tx_1 in block_1['tx'], True)
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
PrioritiseTransactionTest().main()
|