Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc-transaction-ordering.py
Show First 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | class TransactionOrderingTest(BitcoinTestFramework): | ||||
def set_tip(self, number: int): | def set_tip(self, number: int): | ||||
""" | """ | ||||
Move the tip back to a previous block. | Move the tip back to a previous block. | ||||
""" | """ | ||||
self.tip = self.blocks[number] | self.tip = self.blocks[number] | ||||
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()) | ||||
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(): | ||||
spendable_outputs.append(self.tip) | spendable_outputs.append(self.tip) | ||||
Show All 17 Lines | def run_test(self): | ||||
return block | return block | ||||
# shorthand for functions | # shorthand for functions | ||||
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(99): | for i in range(99): | ||||
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()) | ||||
# Let's build some blocks and test them. | # Let's build some blocks and test them. | ||||
for i in range(17): | for i in range(17): | ||||
n = i + 1 | n = i + 1 | ||||
node.p2p.send_blocks_and_test([block(n)], node) | peer.send_blocks_and_test([block(n)], node) | ||||
node.p2p.send_blocks_and_test([block(5556)], node) | peer.send_blocks_and_test([block(5556)], node) | ||||
# Block with regular ordering are now rejected. | # Block with regular ordering are now rejected. | ||||
node.p2p.send_blocks_and_test([block( | peer.send_blocks_and_test([block( | ||||
5557, out[17], tx_count=16)], node, success=False, reject_reason='tx-ordering') | 5557, out[17], tx_count=16)], node, success=False, reject_reason='tx-ordering') | ||||
# Rewind bad block. | # Rewind bad block. | ||||
self.set_tip(5556) | self.set_tip(5556) | ||||
# After we activate the Nov 15, 2018 HF, transaction order is enforced. | # After we activate the Nov 15, 2018 HF, transaction order is enforced. | ||||
def ordered_block(block_number, spend): | def ordered_block(block_number, spend): | ||||
b = block(block_number, spend=spend, tx_count=16) | b = block(block_number, spend=spend, tx_count=16) | ||||
make_conform_to_ctor(b) | make_conform_to_ctor(b) | ||||
update_block(block_number) | update_block(block_number) | ||||
return b | return b | ||||
# Now that the fork activated, we need to order transaction per txid. | # Now that the fork activated, we need to order transaction per txid. | ||||
node.p2p.send_blocks_and_test([ordered_block(4445, out[17])], node) | peer.send_blocks_and_test([ordered_block(4445, out[17])], node) | ||||
node.p2p.send_blocks_and_test([ordered_block(4446, out[18])], node) | peer.send_blocks_and_test([ordered_block(4446, out[18])], node) | ||||
# Generate a block with a duplicated transaction. | # Generate a block with a duplicated transaction. | ||||
double_tx_block = ordered_block(4447, out[19]) | double_tx_block = ordered_block(4447, out[19]) | ||||
assert_equal(len(double_tx_block.vtx), 16) | assert_equal(len(double_tx_block.vtx), 16) | ||||
double_tx_block.vtx = double_tx_block.vtx[:8] + \ | double_tx_block.vtx = double_tx_block.vtx[:8] + \ | ||||
[double_tx_block.vtx[8]] + double_tx_block.vtx[8:] | [double_tx_block.vtx[8]] + double_tx_block.vtx[8:] | ||||
update_block(4447) | update_block(4447) | ||||
node.p2p.send_blocks_and_test( | peer.send_blocks_and_test( | ||||
[self.tip], node, success=False, reject_reason='bad-txns-duplicate') | [self.tip], node, success=False, reject_reason='bad-txns-duplicate') | ||||
# Rewind bad block. | # Rewind bad block. | ||||
self.set_tip(4446) | self.set_tip(4446) | ||||
# Check over two blocks. | # Check over two blocks. | ||||
proper_block = ordered_block(4448, out[20]) | proper_block = ordered_block(4448, out[20]) | ||||
node.p2p.send_blocks_and_test([self.tip], node) | peer.send_blocks_and_test([self.tip], node) | ||||
replay_tx_block = ordered_block(4449, out[21]) | replay_tx_block = ordered_block(4449, out[21]) | ||||
assert_equal(len(replay_tx_block.vtx), 16) | assert_equal(len(replay_tx_block.vtx), 16) | ||||
replay_tx_block.vtx.append(proper_block.vtx[5]) | replay_tx_block.vtx.append(proper_block.vtx[5]) | ||||
replay_tx_block.vtx = [replay_tx_block.vtx[0]] + \ | replay_tx_block.vtx = [replay_tx_block.vtx[0]] + \ | ||||
sorted(replay_tx_block.vtx[1:], key=lambda tx: tx.get_id()) | sorted(replay_tx_block.vtx[1:], key=lambda tx: tx.get_id()) | ||||
update_block(4449) | update_block(4449) | ||||
node.p2p.send_blocks_and_test( | peer.send_blocks_and_test( | ||||
[self.tip], node, success=False, reject_reason='bad-txns-BIP30') | [self.tip], node, success=False, reject_reason='bad-txns-BIP30') | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
TransactionOrderingTest().main() | TransactionOrderingTest().main() |