Changeset View
Changeset View
Standalone View
Standalone View
test/functional/feature_block.py
Show First 20 Lines • Show All 440 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
self.log.info("Reject a block with invalid work") | self.log.info("Reject a block with invalid work") | ||||
self.move_tip(44) | self.move_tip(44) | ||||
b47 = self.next_block(47, solve=False) | b47 = self.next_block(47, solve=False) | ||||
target = uint256_from_compact(b47.nBits) | target = uint256_from_compact(b47.nBits) | ||||
while b47.sha256 < target: | while b47.sha256 < target: | ||||
b47.nNonce += 1 | b47.nNonce += 1 | ||||
b47.rehash() | b47.rehash() | ||||
self.send_blocks([b47], False, request_block=False) | self.send_blocks( | ||||
[b47], | |||||
False, | |||||
force_send=True, | |||||
reject_reason='high-hash') | |||||
self.log.info("Reject a block with a timestamp >2 hours in the future") | self.log.info("Reject a block with a timestamp >2 hours in the future") | ||||
self.move_tip(44) | self.move_tip(44) | ||||
b48 = self.next_block(48, solve=False) | b48 = self.next_block(48, solve=False) | ||||
b48.nTime = int(time.time()) + 60 * 60 * 3 | b48.nTime = int(time.time()) + 60 * 60 * 3 | ||||
b48.solve() | b48.solve() | ||||
self.send_blocks([b48], False, request_block=False) | self.send_blocks([b48], False, force_send=True, | ||||
reject_reason='time-too-new') | |||||
self.log.info("Reject a block with invalid merkle hash") | self.log.info("Reject a block with invalid merkle hash") | ||||
self.move_tip(44) | self.move_tip(44) | ||||
b49 = self.next_block(49) | b49 = self.next_block(49) | ||||
b49.hashMerkleRoot += 1 | b49.hashMerkleRoot += 1 | ||||
b49.solve() | b49.solve() | ||||
self.send_blocks([b49], success=False, | self.send_blocks([b49], success=False, | ||||
reject_reason='bad-txnmrklroot', reconnect=True) | reject_reason='bad-txnmrklroot', reconnect=True) | ||||
self.log.info("Reject a block with incorrect POW limit") | self.log.info("Reject a block with incorrect POW limit") | ||||
self.move_tip(44) | self.move_tip(44) | ||||
b50 = self.next_block(50) | b50 = self.next_block(50) | ||||
b50.nBits = b50.nBits - 1 | b50.nBits = b50.nBits - 1 | ||||
b50.solve() | b50.solve() | ||||
self.send_blocks([b50], False, request_block=False, reconnect=True) | self.send_blocks( | ||||
[b50], | |||||
False, | |||||
force_send=True, | |||||
reject_reason='bad-diffbits', | |||||
reconnect=True) | |||||
self.log.info("Reject a block with two coinbase transactions") | self.log.info("Reject a block with two coinbase transactions") | ||||
self.move_tip(44) | self.move_tip(44) | ||||
b51 = self.next_block(51) | b51 = self.next_block(51) | ||||
cb2 = create_coinbase(51, self.coinbase_pubkey) | cb2 = create_coinbase(51, self.coinbase_pubkey) | ||||
b51 = self.update_block(51, [cb2]) | b51 = self.update_block(51, [cb2]) | ||||
self.send_blocks([b51], success=False, | self.send_blocks([b51], success=False, | ||||
reject_reason='bad-tx-coinbase', reconnect=True) | reject_reason='bad-tx-coinbase', reconnect=True) | ||||
Show All 13 Lines | def run_test(self): | ||||
b53 = self.next_block(53, spend=out[14]) | b53 = self.next_block(53, spend=out[14]) | ||||
self.send_blocks([b53], False) | self.send_blocks([b53], False) | ||||
self.save_spendable_output() | self.save_spendable_output() | ||||
self.log.info("Reject a block with timestamp before MedianTimePast") | self.log.info("Reject a block with timestamp before MedianTimePast") | ||||
b54 = self.next_block(54, spend=out[15]) | b54 = self.next_block(54, spend=out[15]) | ||||
b54.nTime = b35.nTime - 1 | b54.nTime = b35.nTime - 1 | ||||
b54.solve() | b54.solve() | ||||
self.send_blocks([b54], False, request_block=False) | self.send_blocks([b54], False, force_send=True, | ||||
reject_reason='time-too-old') | |||||
# valid timestamp | # valid timestamp | ||||
self.move_tip(53) | self.move_tip(53) | ||||
b55 = self.next_block(55, spend=out[15]) | b55 = self.next_block(55, spend=out[15]) | ||||
b55.nTime = b35.nTime | b55.nTime = b35.nTime | ||||
self.update_block(55, []) | self.update_block(55, []) | ||||
self.send_blocks([b55], True) | self.send_blocks([b55], True) | ||||
self.save_spendable_output() | self.save_spendable_output() | ||||
▲ Show 20 Lines • Show All 203 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0))) | tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0))) | ||||
b64a = self.update_block("64a", [tx]) | b64a = self.update_block("64a", [tx]) | ||||
assert_equal(len(b64a.serialize()), LEGACY_MAX_BLOCK_SIZE + 8) | assert_equal(len(b64a.serialize()), LEGACY_MAX_BLOCK_SIZE + 8) | ||||
self.send_blocks([b64a], success=False, | self.send_blocks([b64a], success=False, | ||||
reject_reason='non-canonical ReadCompactSize()') | reject_reason='non-canonical ReadCompactSize()') | ||||
# bitcoind doesn't disconnect us for sending a bloated block, but if we subsequently | # bitcoind doesn't disconnect us for sending a bloated block, but if we subsequently | ||||
# resend the header message, it won't send us the getdata message again. Just | # resend the header message, it won't send us the getdata message again. Just | ||||
# disconnect and reconnect and then call sync_blocks. | # disconnect and reconnect and then call send_blocks. | ||||
# TODO: improve this test to be less dependent on P2P DOS behaviour. | # TODO: improve this test to be less dependent on P2P DOS behaviour. | ||||
node.disconnect_p2ps() | node.disconnect_p2ps() | ||||
self.reconnect_p2p() | self.reconnect_p2p() | ||||
self.move_tip(60) | self.move_tip(60) | ||||
b64 = CBlock(b64a) | b64 = CBlock(b64a) | ||||
b64.vtx = copy.deepcopy(b64a.vtx) | b64.vtx = copy.deepcopy(b64a.vtx) | ||||
assert_equal(b64.hash, b64a.hash) | assert_equal(b64.hash, b64a.hash) | ||||
▲ Show 20 Lines • Show All 163 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
b79 = self.update_block(79, [tx79]) | b79 = self.update_block(79, [tx79]) | ||||
self.send_blocks([b79], True) | self.send_blocks([b79], True) | ||||
# mempool should be empty | # mempool should be empty | ||||
assert_equal(len(self.nodes[0].getrawmempool()), 0) | assert_equal(len(self.nodes[0].getrawmempool()), 0) | ||||
self.move_tip(77) | self.move_tip(77) | ||||
b80 = self.next_block(80, spend=out[25]) | b80 = self.next_block(80, spend=out[25]) | ||||
self.send_blocks([b80], False, request_block=False) | self.send_blocks([b80], False, force_send=True) | ||||
self.save_spendable_output() | self.save_spendable_output() | ||||
b81 = self.next_block(81, spend=out[26]) | b81 = self.next_block(81, spend=out[26]) | ||||
# other chain is same length | # other chain is same length | ||||
self.send_blocks([b81], False, request_block=False) | self.send_blocks([b81], False, force_send=True) | ||||
self.save_spendable_output() | self.save_spendable_output() | ||||
b82 = self.next_block(82, spend=out[27]) | b82 = self.next_block(82, spend=out[27]) | ||||
# now this chain is longer, triggers re-org | # now this chain is longer, triggers re-org | ||||
self.send_blocks([b82], True) | self.send_blocks([b82], True) | ||||
self.save_spendable_output() | self.save_spendable_output() | ||||
# now check that tx78 and tx79 have been put back into the peer's | # now check that tx78 and tx79 have been put back into the peer's | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
self.send_blocks(blocks, True, timeout=960) | self.send_blocks(blocks, True, timeout=960) | ||||
chain1_tip = i | chain1_tip = i | ||||
# now create alt chain of same length | # now create alt chain of same length | ||||
self.move_tip(88) | self.move_tip(88) | ||||
blocks2 = [] | blocks2 = [] | ||||
for i in range(89, LARGE_REORG_SIZE + 89): | for i in range(89, LARGE_REORG_SIZE + 89): | ||||
blocks2.append(self.next_block("alt" + str(i))) | blocks2.append(self.next_block("alt" + str(i))) | ||||
self.send_blocks(blocks2, False, request_block=False) | self.send_blocks(blocks2, False, force_send=True) | ||||
# extend alt chain to trigger re-org | # extend alt chain to trigger re-org | ||||
block = self.next_block("alt" + str(chain1_tip + 1)) | block = self.next_block("alt" + str(chain1_tip + 1)) | ||||
self.send_blocks([block], True, timeout=960) | self.send_blocks([block], True, timeout=960) | ||||
# ... and re-org back to the first chain | # ... and re-org back to the first chain | ||||
self.move_tip(chain1_tip) | self.move_tip(chain1_tip) | ||||
block = self.next_block(chain1_tip + 1) | block = self.next_block(chain1_tip + 1) | ||||
self.send_blocks([block], False, request_block=False) | self.send_blocks([block], False, force_send=True) | ||||
block = self.next_block(chain1_tip + 2) | block = self.next_block(chain1_tip + 2) | ||||
self.send_blocks([block], True, timeout=960) | self.send_blocks([block], True, timeout=960) | ||||
# Helper methods | # Helper methods | ||||
################ | ################ | ||||
def add_transactions_to_block(self, block, tx_list): | def add_transactions_to_block(self, block, tx_list): | ||||
[tx.rehash() for tx in tx_list] | [tx.rehash() for tx in tx_list] | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | def reconnect_p2p(self): | ||||
"""Tear down and bootstrap the P2P connection to the node. | """Tear down and bootstrap the P2P connection to the node. | ||||
The node gets disconnected several times in this test. This helper | The node gets disconnected several times in this test. This helper | ||||
method reconnects the p2p and restarts the network thread.""" | method reconnects the p2p and restarts the network thread.""" | ||||
self.nodes[0].disconnect_p2ps() | self.nodes[0].disconnect_p2ps() | ||||
self.bootstrap_p2p() | self.bootstrap_p2p() | ||||
def send_blocks(self, blocks, success=True, reject_reason=None, | def send_blocks(self, blocks, success=True, reject_reason=None, | ||||
request_block=True, reconnect=False, timeout=60): | force_send=False, reconnect=False, timeout=60): | ||||
"""Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block. | """Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block. | ||||
Call with success = False if the tip shouldn't advance to the most recent block.""" | Call with success = False if the tip shouldn't advance to the most recent block.""" | ||||
self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success, | self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success, | ||||
reject_reason=reject_reason, request_block=request_block, timeout=timeout, expect_disconnect=reconnect) | reject_reason=reject_reason, force_send=force_send, timeout=timeout, expect_disconnect=reconnect) | ||||
if reconnect: | if reconnect: | ||||
self.reconnect_p2p() | self.reconnect_p2p() | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
FullBlockTest().main() | FullBlockTest().main() |