Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc-mempool-coherence-on-activations.py
Show First 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | def next_block(self, number): | ||||
self.tip = block | self.tip = block | ||||
self.block_heights[block.sha256] = height | self.block_heights[block.sha256] = height | ||||
assert number not in self.blocks | assert number not in self.blocks | ||||
self.blocks[number] = block | self.blocks[number] = block | ||||
return block | return block | ||||
def run_test(self): | def run_test(self): | ||||
node = self.nodes[0] | node = self.nodes[0] | ||||
node.add_p2p_connection(P2PDataStore()) | peer = node.add_p2p_connection(P2PDataStore()) | ||||
node.setmocktime(ACTIVATION_TIME) | node.setmocktime(ACTIVATION_TIME) | ||||
self.genesis_hash = int(node.getbestblockhash(), 16) | self.genesis_hash = int(node.getbestblockhash(), 16) | ||||
self.block_heights[self.genesis_hash] = 0 | self.block_heights[self.genesis_hash] = 0 | ||||
spendable_outputs = [] | spendable_outputs = [] | ||||
# save the current tip so it can be spent by a later block | # save the current tip so it can be spent by a later block | ||||
def save_spendable_output(): | def save_spendable_output(): | ||||
Show All 39 Lines | def run_test(self): | ||||
return tx, PreviousSpendableOutput(tx, 0) | return tx, PreviousSpendableOutput(tx, 0) | ||||
# shorthand | # shorthand | ||||
block = self.next_block | block = self.next_block | ||||
# Create a new block | # Create a new block | ||||
block(0) | block(0) | ||||
save_spendable_output() | save_spendable_output() | ||||
node.p2p.send_blocks_and_test([self.tip], node) | peer.send_blocks_and_test([self.tip], node) | ||||
# Now we need that block to mature so we can spend the coinbase. | # Now we need that block to mature so we can spend the coinbase. | ||||
maturity_blocks = [] | maturity_blocks = [] | ||||
for i in range(110): | for i in range(110): | ||||
block(5000 + i) | block(5000 + i) | ||||
maturity_blocks.append(self.tip) | maturity_blocks.append(self.tip) | ||||
save_spendable_output() | save_spendable_output() | ||||
node.p2p.send_blocks_and_test(maturity_blocks, node) | peer.send_blocks_and_test(maturity_blocks, node) | ||||
# collect spendable outputs now to avoid cluttering the code later on | # collect spendable outputs now to avoid cluttering the code later on | ||||
out = [] | out = [] | ||||
for i in range(100): | for i in range(100): | ||||
out.append(get_spendable_output()) | out.append(get_spendable_output()) | ||||
# Create 2 pre-fork-only txns (tx_pre0, tx_pre1). Fund txns are valid | # Create 2 pre-fork-only txns (tx_pre0, tx_pre1). Fund txns are valid | ||||
# pre-fork, so we can mine them right away. | # pre-fork, so we can mine them right away. | ||||
txfund0, tx_pre0 = create_fund_and_pre_fork_only_tx(out[0]) | txfund0, tx_pre0 = create_fund_and_pre_fork_only_tx(out[0]) | ||||
txfund1, tx_pre1 = create_fund_and_pre_fork_only_tx(out[1]) | txfund1, tx_pre1 = create_fund_and_pre_fork_only_tx(out[1]) | ||||
# Create 2 post-fork-only txns (tx_post0, tx_post1). Fund txns are | # Create 2 post-fork-only txns (tx_post0, tx_post1). Fund txns are | ||||
# valid pre-fork, so we can mine them right away. | # valid pre-fork, so we can mine them right away. | ||||
txfund2, tx_post0 = create_fund_and_post_fork_only_tx(out[2]) | txfund2, tx_post0 = create_fund_and_post_fork_only_tx(out[2]) | ||||
txfund3, tx_post1 = create_fund_and_post_fork_only_tx(out[3]) | txfund3, tx_post1 = create_fund_and_post_fork_only_tx(out[3]) | ||||
# Create blocks to activate the fork. Mine all funding transactions. | # Create blocks to activate the fork. Mine all funding transactions. | ||||
bfork = block(5555) | bfork = block(5555) | ||||
bfork.nTime = ACTIVATION_TIME - 1 | bfork.nTime = ACTIVATION_TIME - 1 | ||||
update_block(5555, [txfund0, txfund1, txfund2, txfund3]) | update_block(5555, [txfund0, txfund1, txfund2, txfund3]) | ||||
node.p2p.send_blocks_and_test([self.tip], node) | peer.send_blocks_and_test([self.tip], node) | ||||
for i in range(5): | for i in range(5): | ||||
node.p2p.send_blocks_and_test([block(5200 + i)], node) | peer.send_blocks_and_test([block(5200 + i)], node) | ||||
# Check we are just before the activation time | # Check we are just before the activation time | ||||
assert_equal( | assert_equal( | ||||
node.getblockchaininfo()['mediantime'], | node.getblockchaininfo()['mediantime'], | ||||
ACTIVATION_TIME - 1) | ACTIVATION_TIME - 1) | ||||
# We are just before the fork. Pre-fork-only and always-valid chained | # We are just before the fork. Pre-fork-only and always-valid chained | ||||
# txns (tx_chain0, tx_chain1) are valid, post-fork-only txns are | # txns (tx_chain0, tx_chain1) are valid, post-fork-only txns are | ||||
Show All 10 Lines | def run_test(self): | ||||
assert_raises_rpc_error(-26, RPC_EXPECTED_ERROR, | assert_raises_rpc_error(-26, RPC_EXPECTED_ERROR, | ||||
node.sendrawtransaction, ToHex(tx_post1)) | node.sendrawtransaction, ToHex(tx_post1)) | ||||
check_mempool_equal([tx_chain0, tx_chain1, tx_pre0, tx_pre1]) | check_mempool_equal([tx_chain0, tx_chain1, tx_pre0, tx_pre1]) | ||||
# Activate the fork. Mine the 1st always-valid chained txn and a | # Activate the fork. Mine the 1st always-valid chained txn and a | ||||
# pre-fork-only txn. | # pre-fork-only txn. | ||||
block(5556) | block(5556) | ||||
update_block(5556, [tx_chain0, tx_pre0]) | update_block(5556, [tx_chain0, tx_pre0]) | ||||
node.p2p.send_blocks_and_test([self.tip], node) | peer.send_blocks_and_test([self.tip], node) | ||||
forkblockid = node.getbestblockhash() | forkblockid = node.getbestblockhash() | ||||
# Check we just activated the fork | # Check we just activated the fork | ||||
assert_equal(node.getblockheader(forkblockid)['mediantime'], | assert_equal(node.getblockheader(forkblockid)['mediantime'], | ||||
ACTIVATION_TIME) | ACTIVATION_TIME) | ||||
# Check mempool coherence when activating the fork. Pre-fork-only txns | # Check mempool coherence when activating the fork. Pre-fork-only txns | ||||
# were evicted from the mempool, while always-valid txns remain. | # were evicted from the mempool, while always-valid txns remain. | ||||
# Evicted: tx_pre1 | # Evicted: tx_pre1 | ||||
check_mempool_equal([tx_chain1]) | check_mempool_equal([tx_chain1]) | ||||
# Post-fork-only and always-valid txns are accepted, pre-fork-only txn | # Post-fork-only and always-valid txns are accepted, pre-fork-only txn | ||||
# are rejected. | # are rejected. | ||||
send_transaction_to_mempool(tx_post0) | send_transaction_to_mempool(tx_post0) | ||||
send_transaction_to_mempool(tx_post1) | send_transaction_to_mempool(tx_post1) | ||||
tx_chain2, _ = create_always_valid_chained_tx(last_chained_output) | tx_chain2, _ = create_always_valid_chained_tx(last_chained_output) | ||||
send_transaction_to_mempool(tx_chain2) | send_transaction_to_mempool(tx_chain2) | ||||
assert_raises_rpc_error(-26, RPC_EXPECTED_ERROR, | assert_raises_rpc_error(-26, RPC_EXPECTED_ERROR, | ||||
node.sendrawtransaction, ToHex(tx_pre1)) | node.sendrawtransaction, ToHex(tx_pre1)) | ||||
check_mempool_equal([tx_chain1, tx_chain2, tx_post0, tx_post1]) | check_mempool_equal([tx_chain1, tx_chain2, tx_post0, tx_post1]) | ||||
# Mine the 2nd always-valid chained txn and a post-fork-only txn. | # Mine the 2nd always-valid chained txn and a post-fork-only txn. | ||||
block(5557) | block(5557) | ||||
update_block(5557, [tx_chain1, tx_post0]) | update_block(5557, [tx_chain1, tx_post0]) | ||||
node.p2p.send_blocks_and_test([self.tip], node) | peer.send_blocks_and_test([self.tip], node) | ||||
postforkblockid = node.getbestblockhash() | postforkblockid = node.getbestblockhash() | ||||
# The mempool contains the 3rd chained txn and a post-fork-only txn. | # The mempool contains the 3rd chained txn and a post-fork-only txn. | ||||
check_mempool_equal([tx_chain2, tx_post1]) | check_mempool_equal([tx_chain2, tx_post1]) | ||||
# In the following we will testing block disconnections and reorgs. | # In the following we will testing block disconnections and reorgs. | ||||
# - tx_chain2 will always be retained in the mempool since it is always | # - tx_chain2 will always be retained in the mempool since it is always | ||||
# valid. Its continued presence shows that we are never simply | # valid. Its continued presence shows that we are never simply | ||||
# clearing the entire mempool. | # clearing the entire mempool. | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
# This starts after 5204, so it contains neither the forkblockid nor | # This starts after 5204, so it contains neither the forkblockid nor | ||||
# the postforkblockid from above. | # the postforkblockid from above. | ||||
self.tip = self.blocks[5204] | self.tip = self.blocks[5204] | ||||
reorg_blocks = [] | reorg_blocks = [] | ||||
for i in range(3): | for i in range(3): | ||||
reorg_blocks.append(block(5900 + i)) | reorg_blocks.append(block(5900 + i)) | ||||
# Perform the reorg | # Perform the reorg | ||||
node.p2p.send_blocks_and_test(reorg_blocks, node) | peer.send_blocks_and_test(reorg_blocks, node) | ||||
# reorg finishes after the fork | # reorg finishes after the fork | ||||
assert_equal( | assert_equal( | ||||
node.getblockchaininfo()['mediantime'], | node.getblockchaininfo()['mediantime'], | ||||
ACTIVATION_TIME + 2) | ACTIVATION_TIME + 2) | ||||
# In old mempool: tx_chain2, tx_post1 | # In old mempool: tx_chain2, tx_post1 | ||||
# Recovered from blocks: tx_chain0, tx_chain1, tx_post0 | # Recovered from blocks: tx_chain0, tx_chain1, tx_post0 | ||||
# Lost from blocks: tx_pre0 | # Lost from blocks: tx_pre0 | ||||
# Retained from old mempool: tx_chain2, tx_post1 | # Retained from old mempool: tx_chain2, tx_post1 | ||||
# Evicted from old mempool: NONE | # Evicted from old mempool: NONE | ||||
check_mempool_equal( | check_mempool_equal( | ||||
[tx_chain0, tx_chain1, tx_chain2, tx_post0, tx_post1]) | [tx_chain0, tx_chain1, tx_chain2, tx_post0, tx_post1]) | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
MempoolCoherenceOnActivationsTest().main() | MempoolCoherenceOnActivationsTest().main() |