Changeset View
Changeset View
Standalone View
Standalone View
test/functional/invalidblockrequest.py
Show All 30 Lines | def set_test_params(self): | ||||
self.num_nodes = 1 | self.num_nodes = 1 | ||||
self.setup_clean_chain = True | self.setup_clean_chain = True | ||||
def run_test(self): | def run_test(self): | ||||
test = TestManager(self, self.options.tmpdir) | test = TestManager(self, self.options.tmpdir) | ||||
test.add_all_connections(self.nodes) | test.add_all_connections(self.nodes) | ||||
self.tip = None | self.tip = None | ||||
self.block_time = None | self.block_time = None | ||||
self.extra_args = [["-whitelist=127.0.0.1"]] | |||||
NetworkThread().start() # Start up network handling in another thread | NetworkThread().start() # Start up network handling in another thread | ||||
test.run() | test.run() | ||||
def get_tests(self): | def get_tests(self): | ||||
if self.tip is None: | if self.tip is None: | ||||
self.tip = int("0x" + self.nodes[0].getbestblockhash(), 0) | self.tip = int("0x" + self.nodes[0].getbestblockhash(), 0) | ||||
self.block_time = int(time.time()) + 1 | self.block_time = int(time.time()) + 1 | ||||
''' | ''' | ||||
Create a new block with an anyone-can-spend coinbase | Create a new block with an anyone-can-spend coinbase | ||||
''' | ''' | ||||
height = 1 | height = 1 | ||||
block = create_block( | block = create_block( | ||||
self.tip, create_coinbase(height), self.block_time) | self.tip, create_coinbase(height), self.block_time) | ||||
self.block_time += 1 | self.block_time += 1 | ||||
block.solve() | block.solve() | ||||
# Save the coinbase for later | |||||
self.block1 = block | |||||
self.tip = block.sha256 | self.tip = block.sha256 | ||||
height += 1 | height += 1 | ||||
yield TestInstance([[block, True]]) | yield TestInstance([[block, True]]) | ||||
block1 = block | |||||
''' | ''' | ||||
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. | ||||
''' | ''' | ||||
test = TestInstance(sync_every_block=False) | test = TestInstance(sync_every_block=False) | ||||
for i in range(100): | for i in range(100): | ||||
block = create_block( | block = create_block( | ||||
self.tip, create_coinbase(height), self.block_time) | self.tip, create_coinbase(height), self.block_time) | ||||
block.solve() | block.solve() | ||||
self.tip = block.sha256 | self.tip = block.sha256 | ||||
self.block_time += 1 | self.block_time += 1 | ||||
test.blocks_and_transactions.append([block, True]) | test.blocks_and_transactions.append([block, True]) | ||||
height += 1 | height += 1 | ||||
yield test | yield test | ||||
assert(block.sha256 == int(self.nodes[0].getbestblockhash(), 16)) | |||||
''' | ''' | ||||
Now we use merkle-root malleability to generate an invalid block with | Now we use merkle-root malleability to generate an invalid block with | ||||
same blockheader. | same blockheader. | ||||
Manufacture a block with 3 transactions (coinbase, spend of prior | Manufacture a block with 3 transactions (coinbase, spend of prior | ||||
coinbase, spend of that spend). Duplicate the 3rd transaction to | coinbase, spend of that spend). Duplicate the 3rd transaction to | ||||
leave merkle root and blockheader unchanged but invalidate the block. | leave merkle root and blockheader unchanged but invalidate the block. | ||||
''' | ''' | ||||
block2 = create_block( | block2 = create_block( | ||||
self.tip, create_coinbase(height), self.block_time) | self.tip, create_coinbase(height), self.block_time) | ||||
self.block_time += 1 | self.block_time += 1 | ||||
# b'0x51' is OP_TRUE | # b'0x51' is OP_TRUE | ||||
tx1 = create_transaction(self.block1.vtx[0], 0, b'\x51', 50 * COIN) | tx1 = create_transaction(block1.vtx[0], 0, b'', 50 * COIN) | ||||
tx2 = create_transaction(tx1, 0, b'\x51', 50 * COIN) | tx2 = create_transaction(tx1, 0, b'\x51', 50 * COIN) | ||||
block2.vtx.extend([tx1, tx2]) | block2.vtx.extend([tx1, tx2]) | ||||
block2.vtx = [block2.vtx[0]] + \ | |||||
sorted(block2.vtx[1:], key=lambda tx: tx.get_id()) | |||||
block2.hashMerkleRoot = block2.calc_merkle_root() | block2.hashMerkleRoot = block2.calc_merkle_root() | ||||
block2.rehash() | block2.rehash() | ||||
block2.solve() | block2.solve() | ||||
orig_hash = block2.sha256 | orig_hash = block2.sha256 | ||||
block2_orig = copy.deepcopy(block2) | block2_orig = copy.deepcopy(block2) | ||||
# Mutate block 2 | # Mutate block 2 | ||||
block2.vtx.append(tx2) | block2.vtx.append(block2.vtx[2]) | ||||
assert_equal(block2.hashMerkleRoot, block2.calc_merkle_root()) | assert_equal(block2.hashMerkleRoot, block2.calc_merkle_root()) | ||||
assert_equal(orig_hash, block2.rehash()) | assert_equal(orig_hash, block2.rehash()) | ||||
assert(block2_orig.vtx != block2.vtx) | assert(block2_orig.vtx != block2.vtx) | ||||
self.tip = block2.sha256 | self.tip = block2.sha256 | ||||
yield TestInstance([[block2, RejectResult(16, b'bad-txns-duplicate')], [block2_orig, True]]) | |||||
yield TestInstance([[block2, RejectResult(16, b'bad-txns-duplicate')]]) | |||||
yield TestInstance([[block2_orig, True]]) | |||||
height += 1 | height += 1 | ||||
# Check transactions for duplicate inputs | # Check transactions for duplicate inputs | ||||
self.log.info("Test duplicate input block.") | self.log.info("Test duplicate input block.") | ||||
block2_orig.vtx[2].vin.append(block2_orig.vtx[2].vin[0]) | block2_orig.vtx[2].vin.append(block2_orig.vtx[2].vin[0]) | ||||
block2.vtx = [block2.vtx[0]] + \ | |||||
sorted(block2.vtx[1:], key=lambda tx: tx.get_id()) | |||||
block2_orig.vtx[2].rehash() | block2_orig.vtx[2].rehash() | ||||
block2_orig.hashMerkleRoot = block2_orig.calc_merkle_root() | block2_orig.hashMerkleRoot = block2_orig.calc_merkle_root() | ||||
block2_orig.rehash() | block2_orig.rehash() | ||||
block2_orig.solve() | block2_orig.solve() | ||||
yield TestInstance([[block2_orig, RejectResult(16, b'bad-txns-inputs-duplicate')]]) | yield TestInstance([[block2_orig, RejectResult(16, b'bad-txns-inputs-duplicate')]]) | ||||
''' | ''' | ||||
Make sure that a totally screwed up block is not valid. | Make sure that a totally screwed up block is not valid. | ||||
''' | ''' | ||||
block3 = create_block( | block3 = create_block( | ||||
self.tip, create_coinbase(height), self.block_time) | self.tip, create_coinbase(height), self.block_time) | ||||
self.block_time += 1 | self.block_time += 1 | ||||
block3.vtx[0].vout[0].nValue = 100 * COIN # Too high! | block3.vtx[0].vout[0].nValue = 51 * COIN # Too high! | ||||
block3.vtx[0].sha256 = None | block3.vtx[0].sha256 = None | ||||
block3.vtx[0].calc_sha256() | block3.vtx[0].calc_sha256() | ||||
block3.hashMerkleRoot = block3.calc_merkle_root() | block3.hashMerkleRoot = block3.calc_merkle_root() | ||||
block3.rehash() | block3.rehash() | ||||
block3.solve() | block3.solve() | ||||
yield TestInstance([[block3, RejectResult(16, b'bad-cb-amount')]]) | yield TestInstance([[block3, RejectResult(16, b'bad-cb-amount')]]) | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
InvalidBlockRequestTest().main() | InvalidBlockRequestTest().main() |