Browse Source
Mempool improvements, branch ID awareness Whenever the local chain tip is updated, transactions in the mempool which commit to an unmineable branch ID (for example, just before a network upgrade activates, where the next block will have a different branch ID) will be removed. Includes commits cherry-picked from the following upstream PRs: - bitcoin/bitcoin#6654 - Only the mempool index change. - bitcoin/bitcoin#6776 - bitcoin/bitcoin#7020 - bitcoin/bitcoin#6915 Part of #2074.pull/4/head
Homu
6 years ago
17 changed files with 537 additions and 127 deletions
@ -0,0 +1,119 @@ |
|||||
|
#!/usr/bin/env python2 |
||||
|
# Copyright (c) 2018 The Zcash developers |
||||
|
# Distributed under the MIT software license, see the accompanying |
||||
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php. |
||||
|
|
||||
|
from test_framework.test_framework import BitcoinTestFramework |
||||
|
from test_framework.util import assert_equal, initialize_chain_clean, \ |
||||
|
start_node, connect_nodes, wait_and_assert_operationid_status |
||||
|
|
||||
|
from decimal import Decimal |
||||
|
|
||||
|
# Test mempool behaviour around network upgrade activation |
||||
|
class MempoolUpgradeActivationTest(BitcoinTestFramework): |
||||
|
|
||||
|
alert_filename = None # Set by setup_network |
||||
|
|
||||
|
def setup_network(self): |
||||
|
args = ["-checkmempool", "-debug=mempool", "-blockmaxsize=4000", "-nuparams=5ba81b19:200"] |
||||
|
self.nodes = [] |
||||
|
self.nodes.append(start_node(0, self.options.tmpdir, args)) |
||||
|
self.nodes.append(start_node(1, self.options.tmpdir, args)) |
||||
|
connect_nodes(self.nodes[1], 0) |
||||
|
self.is_network_split = False |
||||
|
self.sync_all |
||||
|
|
||||
|
def setup_chain(self): |
||||
|
print "Initializing test directory "+self.options.tmpdir |
||||
|
initialize_chain_clean(self.options.tmpdir, 2) |
||||
|
|
||||
|
def run_test(self): |
||||
|
self.nodes[1].generate(100) |
||||
|
self.sync_all() |
||||
|
|
||||
|
# Mine 97 blocks. After this, nodes[1] blocks |
||||
|
# 1 to 97 are spend-able. |
||||
|
self.nodes[0].generate(97) |
||||
|
self.sync_all() |
||||
|
|
||||
|
# Shield some ZEC |
||||
|
node1_taddr = self.nodes[1].getnewaddress() |
||||
|
node0_zaddr = self.nodes[0].z_getnewaddress() |
||||
|
recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}] |
||||
|
myopid = self.nodes[1].z_sendmany(node1_taddr, recipients, 1, Decimal('0')) |
||||
|
print wait_and_assert_operationid_status(self.nodes[1], myopid) |
||||
|
self.sync_all() |
||||
|
|
||||
|
# Mine block 198. After this, the mempool expects |
||||
|
# block 199, which is the last Sprout block. |
||||
|
self.nodes[0].generate(1) |
||||
|
self.sync_all() |
||||
|
|
||||
|
# Mempool should be empty. |
||||
|
assert_equal(set(self.nodes[0].getrawmempool()), set()) |
||||
|
|
||||
|
# Check node 0 shielded balance |
||||
|
assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) |
||||
|
|
||||
|
# Fill the mempool with twice as many transactions as can fit into blocks |
||||
|
node0_taddr = self.nodes[0].getnewaddress() |
||||
|
sprout_txids = [] |
||||
|
while self.nodes[1].getmempoolinfo()['bytes'] < 2 * 4000: |
||||
|
sprout_txids.append(self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001'))) |
||||
|
self.sync_all() |
||||
|
|
||||
|
# Spends should be in the mempool |
||||
|
sprout_mempool = set(self.nodes[0].getrawmempool()) |
||||
|
assert_equal(sprout_mempool, set(sprout_txids)) |
||||
|
|
||||
|
# Mine block 199. After this, the mempool expects |
||||
|
# block 200, which is the first Overwinter block. |
||||
|
self.nodes[0].generate(1) |
||||
|
self.sync_all() |
||||
|
|
||||
|
# mempool should be empty. |
||||
|
assert_equal(set(self.nodes[0].getrawmempool()), set()) |
||||
|
|
||||
|
# Block 199 should contain a subset of the original mempool |
||||
|
# (with all other transactions having been dropped) |
||||
|
block_txids = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['tx'] |
||||
|
assert(len(block_txids) < len(sprout_txids)) |
||||
|
for txid in block_txids[1:]: # Exclude coinbase |
||||
|
assert(txid in sprout_txids) |
||||
|
|
||||
|
# Create some transparent Overwinter transactions |
||||
|
overwinter_txids = [self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')) for i in range(10)] |
||||
|
self.sync_all() |
||||
|
|
||||
|
# Create a shielded Overwinter transaction |
||||
|
recipients = [{'address': node0_taddr, 'amount': Decimal('10')}] |
||||
|
myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients, 1, Decimal('0')) |
||||
|
shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) |
||||
|
assert(shielded != None) |
||||
|
overwinter_txids.append(shielded) |
||||
|
self.sync_all() |
||||
|
|
||||
|
# Spends should be in the mempool |
||||
|
assert_equal(set(self.nodes[0].getrawmempool()), set(overwinter_txids)) |
||||
|
|
||||
|
# Node 0 note should be unspendable |
||||
|
assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('0')) |
||||
|
|
||||
|
# Invalidate block 199. |
||||
|
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) |
||||
|
|
||||
|
# BUG: Ideally, the mempool should now only contain the transactions |
||||
|
# that were in block 199, the Overwinter transactions having been dropped. |
||||
|
# However, because chainActive is not updated until after the transactions |
||||
|
# in the disconnected block have been re-added to the mempool, the height |
||||
|
# seen by AcceptToMemoryPool is one greater than it should be. This causes |
||||
|
# the block 199 transactions to be validated against the Overwinter rules, |
||||
|
# and rejected because they (obviously) fail. |
||||
|
#assert_equal(set(self.nodes[0].getrawmempool()), set(block_txids[1:])) |
||||
|
assert_equal(set(self.nodes[0].getrawmempool()), set()) |
||||
|
|
||||
|
# Node 0 note should be spendable again |
||||
|
assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) |
||||
|
|
||||
|
if __name__ == '__main__': |
||||
|
MempoolUpgradeActivationTest().main() |
Loading…
Reference in new issue