Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc-p2p-fullblocktest-sigops.py
- This file was copied from test/functional/abc-p2p-fullblocktest.py.
Show All 27 Lines | |||||
) | ) | ||||
from test_framework.key import CECKey | from test_framework.key import CECKey | ||||
from test_framework.messages import ( | from test_framework.messages import ( | ||||
COutPoint, | COutPoint, | ||||
CTransaction, | CTransaction, | ||||
CTxIn, | CTxIn, | ||||
CTxOut, | CTxOut, | ||||
ser_compact_size, | ser_compact_size, | ||||
ToHex, | |||||
) | ) | ||||
from test_framework.mininode import P2PDataStore | from test_framework.mininode import P2PDataStore | ||||
from test_framework.script import ( | from test_framework.script import ( | ||||
CScript, | CScript, | ||||
hash160, | hash160, | ||||
OP_2DUP, | OP_2DUP, | ||||
OP_CHECKSIG, | OP_CHECKSIG, | ||||
OP_CHECKSIGVERIFY, | OP_CHECKSIGVERIFY, | ||||
▲ Show 20 Lines • Show All 194 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
# 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) | node.p2p.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(105): | ||||
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) | node.p2p.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. | |||||
for i in range(16): | |||||
n = i + 1 | |||||
block(n, spend=out[i], block_size=n * ONE_MEGABYTE) | |||||
node.p2p.send_blocks_and_test([self.tip], node) | |||||
# block of maximal size | |||||
block(17, spend=out[16], block_size=self.excessive_block_size) | |||||
node.p2p.send_blocks_and_test([self.tip], node) | |||||
# Reject oversized blocks with bad-blk-length error | |||||
block(18, spend=out[17], block_size=self.excessive_block_size + 1) | |||||
node.p2p.send_blocks_and_test( | |||||
[self.tip], node, success=False, reject_reason='bad-blk-length') | |||||
# Rewind bad block. | |||||
tip(17) | |||||
# Accept many sigops | # Accept many sigops | ||||
lots_of_checksigs = CScript( | lots_of_checksigs = CScript( | ||||
[OP_CHECKSIG] * MAX_BLOCK_SIGOPS_PER_MB) | [OP_CHECKSIG] * MAX_BLOCK_SIGOPS_PER_MB) | ||||
block(19, spend=out[17], script=lots_of_checksigs, | block(19, spend=out[0], script=lots_of_checksigs, | ||||
block_size=ONE_MEGABYTE) | block_size=ONE_MEGABYTE) | ||||
node.p2p.send_blocks_and_test([self.tip], node) | node.p2p.send_blocks_and_test([self.tip], node) | ||||
block(20, spend=out[18], script=lots_of_checksigs, | block(20, spend=out[1], script=lots_of_checksigs, | ||||
block_size=ONE_MEGABYTE, extra_sigops=1) | block_size=ONE_MEGABYTE, extra_sigops=1) | ||||
node.p2p.send_blocks_and_test( | node.p2p.send_blocks_and_test( | ||||
[self.tip], node, success=False, reject_reason='bad-blk-sigops') | [self.tip], node, success=False, reject_reason='bad-blk-sigops') | ||||
# Rewind bad block | # Rewind bad block | ||||
tip(19) | tip(19) | ||||
# Accept 40k sigops per block > 1MB and <= 2MB | # Accept 40k sigops per block > 1MB and <= 2MB | ||||
block(21, spend=out[18], script=lots_of_checksigs, | block(21, spend=out[1], script=lots_of_checksigs, | ||||
extra_sigops=MAX_BLOCK_SIGOPS_PER_MB, block_size=ONE_MEGABYTE + 1) | extra_sigops=MAX_BLOCK_SIGOPS_PER_MB, block_size=ONE_MEGABYTE + 1) | ||||
node.p2p.send_blocks_and_test([self.tip], node) | node.p2p.send_blocks_and_test([self.tip], node) | ||||
# Accept 40k sigops per block > 1MB and <= 2MB | # Accept 40k sigops per block > 1MB and <= 2MB | ||||
block(22, spend=out[19], script=lots_of_checksigs, | block(22, spend=out[2], script=lots_of_checksigs, | ||||
extra_sigops=MAX_BLOCK_SIGOPS_PER_MB, block_size=2 * ONE_MEGABYTE) | extra_sigops=MAX_BLOCK_SIGOPS_PER_MB, block_size=2 * ONE_MEGABYTE) | ||||
node.p2p.send_blocks_and_test([self.tip], node) | node.p2p.send_blocks_and_test([self.tip], node) | ||||
# Reject more than 40k sigops per block > 1MB and <= 2MB. | # Reject more than 40k sigops per block > 1MB and <= 2MB. | ||||
block(23, spend=out[20], script=lots_of_checksigs, | block(23, spend=out[3], script=lots_of_checksigs, | ||||
extra_sigops=MAX_BLOCK_SIGOPS_PER_MB + 1, block_size=ONE_MEGABYTE + 1) | extra_sigops=MAX_BLOCK_SIGOPS_PER_MB + 1, block_size=ONE_MEGABYTE + 1) | ||||
node.p2p.send_blocks_and_test( | node.p2p.send_blocks_and_test( | ||||
[self.tip], node, success=False, reject_reason='bad-blk-sigops') | [self.tip], node, success=False, reject_reason='bad-blk-sigops') | ||||
# Rewind bad block | # Rewind bad block | ||||
tip(22) | tip(22) | ||||
# Reject more than 40k sigops per block > 1MB and <= 2MB. | # Reject more than 40k sigops per block > 1MB and <= 2MB. | ||||
block(24, spend=out[20], script=lots_of_checksigs, | block(24, spend=out[3], script=lots_of_checksigs, | ||||
extra_sigops=MAX_BLOCK_SIGOPS_PER_MB + 1, block_size=2 * ONE_MEGABYTE) | extra_sigops=MAX_BLOCK_SIGOPS_PER_MB + 1, block_size=2 * ONE_MEGABYTE) | ||||
node.p2p.send_blocks_and_test( | node.p2p.send_blocks_and_test( | ||||
[self.tip], node, success=False, reject_reason='bad-blk-sigops') | [self.tip], node, success=False, reject_reason='bad-blk-sigops') | ||||
# Rewind bad block | # Rewind bad block | ||||
tip(22) | tip(22) | ||||
# Accept 60k sigops per block > 2MB and <= 3MB | # Accept 60k sigops per block > 2MB and <= 3MB | ||||
block(25, spend=out[20], script=lots_of_checksigs, extra_sigops=2 * | block(25, spend=out[3], script=lots_of_checksigs, extra_sigops=2 * | ||||
MAX_BLOCK_SIGOPS_PER_MB, block_size=2 * ONE_MEGABYTE + 1) | MAX_BLOCK_SIGOPS_PER_MB, block_size=2 * ONE_MEGABYTE + 1) | ||||
node.p2p.send_blocks_and_test([self.tip], node) | node.p2p.send_blocks_and_test([self.tip], node) | ||||
# Accept 60k sigops per block > 2MB and <= 3MB | # Accept 60k sigops per block > 2MB and <= 3MB | ||||
block(26, spend=out[21], script=lots_of_checksigs, | block(26, spend=out[4], script=lots_of_checksigs, | ||||
extra_sigops=2 * MAX_BLOCK_SIGOPS_PER_MB, block_size=3 * ONE_MEGABYTE) | extra_sigops=2 * MAX_BLOCK_SIGOPS_PER_MB, block_size=3 * ONE_MEGABYTE) | ||||
node.p2p.send_blocks_and_test([self.tip], node) | node.p2p.send_blocks_and_test([self.tip], node) | ||||
# Reject more than 40k sigops per block > 1MB and <= 2MB. | # Reject more than 40k sigops per block > 1MB and <= 2MB. | ||||
block(27, spend=out[22], script=lots_of_checksigs, extra_sigops=2 * | block(27, spend=out[5], script=lots_of_checksigs, extra_sigops=2 * | ||||
MAX_BLOCK_SIGOPS_PER_MB + 1, block_size=2 * ONE_MEGABYTE + 1) | MAX_BLOCK_SIGOPS_PER_MB + 1, block_size=2 * ONE_MEGABYTE + 1) | ||||
node.p2p.send_blocks_and_test( | node.p2p.send_blocks_and_test( | ||||
[self.tip], node, success=False, reject_reason='bad-blk-sigops') | [self.tip], node, success=False, reject_reason='bad-blk-sigops') | ||||
# Rewind bad block | # Rewind bad block | ||||
tip(26) | tip(26) | ||||
# Reject more than 40k sigops per block > 1MB and <= 2MB. | # Reject more than 40k sigops per block > 1MB and <= 2MB. | ||||
block(28, spend=out[22], script=lots_of_checksigs, extra_sigops=2 * | block(28, spend=out[5], script=lots_of_checksigs, extra_sigops=2 * | ||||
MAX_BLOCK_SIGOPS_PER_MB + 1, block_size=3 * ONE_MEGABYTE) | MAX_BLOCK_SIGOPS_PER_MB + 1, block_size=3 * ONE_MEGABYTE) | ||||
node.p2p.send_blocks_and_test( | node.p2p.send_blocks_and_test( | ||||
[self.tip], node, success=False, reject_reason='bad-blk-sigops') | [self.tip], node, success=False, reject_reason='bad-blk-sigops') | ||||
# Rewind bad block | # Rewind bad block | ||||
tip(26) | tip(26) | ||||
# Too many sigops in one txn | # Too many sigops in one txn | ||||
too_many_tx_checksigs = CScript( | too_many_tx_checksigs = CScript( | ||||
[OP_CHECKSIG] * (MAX_BLOCK_SIGOPS_PER_MB + 1)) | [OP_CHECKSIG] * (MAX_BLOCK_SIGOPS_PER_MB + 1)) | ||||
block( | block( | ||||
29, spend=out[22], script=too_many_tx_checksigs, block_size=ONE_MEGABYTE + 1) | 29, spend=out[6], script=too_many_tx_checksigs, block_size=ONE_MEGABYTE + 1) | ||||
node.p2p.send_blocks_and_test( | node.p2p.send_blocks_and_test( | ||||
[self.tip], node, success=False, reject_reason='bad-txn-sigops') | [self.tip], node, success=False, reject_reason='bad-txn-sigops') | ||||
# Rewind bad block | # Rewind bad block | ||||
tip(26) | tip(26) | ||||
# Generate a key pair to test P2SH sigops count | # Generate a key pair to test P2SH sigops count | ||||
private_key = CECKey() | private_key = CECKey() | ||||
private_key.set_secretbytes(b"fatstacks") | private_key.set_secretbytes(b"fatstacks") | ||||
public_key = private_key.get_pubkey() | public_key = private_key.get_pubkey() | ||||
# P2SH | # P2SH | ||||
# Build the redeem script, hash it, use hash to create the p2sh script | # Build the redeem script, hash it, use hash to create the p2sh script | ||||
redeem_script = CScript( | redeem_script = CScript( | ||||
[public_key] + [OP_2DUP, OP_CHECKSIGVERIFY] * 5 + [OP_CHECKSIG]) | [public_key] + [OP_2DUP, OP_CHECKSIGVERIFY] * 5 + [OP_CHECKSIG]) | ||||
redeem_script_hash = hash160(redeem_script) | redeem_script_hash = hash160(redeem_script) | ||||
p2sh_script = CScript([OP_HASH160, redeem_script_hash, OP_EQUAL]) | p2sh_script = CScript([OP_HASH160, redeem_script_hash, OP_EQUAL]) | ||||
# Create a p2sh transaction | # Create a p2sh transaction | ||||
p2sh_tx = self.create_tx(out[22], 1, p2sh_script) | p2sh_tx = self.create_tx(out[6], 1, p2sh_script) | ||||
# Add the transaction to the block | # Add the transaction to the block | ||||
block(30) | block(30) | ||||
update_block(30, [p2sh_tx]) | update_block(30, [p2sh_tx]) | ||||
node.p2p.send_blocks_and_test([self.tip], node) | node.p2p.send_blocks_and_test([self.tip], node) | ||||
# Creates a new transaction using the p2sh transaction included in the | # Creates a new transaction using the p2sh transaction included in the | ||||
# last block | # last block | ||||
Show All 11 Lines | def run_test(self): | ||||
spent_p2sh_tx.rehash() | spent_p2sh_tx.rehash() | ||||
return spent_p2sh_tx | return spent_p2sh_tx | ||||
# Sigops p2sh limit | # Sigops p2sh limit | ||||
p2sh_sigops_limit = MAX_BLOCK_SIGOPS_PER_MB - \ | p2sh_sigops_limit = MAX_BLOCK_SIGOPS_PER_MB - \ | ||||
redeem_script.GetSigOpCount(True) | redeem_script.GetSigOpCount(True) | ||||
# Too many sigops in one p2sh txn | # Too many sigops in one p2sh txn | ||||
too_many_p2sh_sigops = CScript([OP_CHECKSIG] * (p2sh_sigops_limit + 1)) | too_many_p2sh_sigops = CScript([OP_CHECKSIG] * (p2sh_sigops_limit + 1)) | ||||
block(31, spend=out[23], block_size=ONE_MEGABYTE + 1) | block(31, spend=out[7], block_size=ONE_MEGABYTE + 1) | ||||
update_block(31, [spend_p2sh_tx(too_many_p2sh_sigops)]) | update_block(31, [spend_p2sh_tx(too_many_p2sh_sigops)]) | ||||
node.p2p.send_blocks_and_test( | node.p2p.send_blocks_and_test( | ||||
[self.tip], node, success=False, reject_reason='bad-txn-sigops') | [self.tip], node, success=False, reject_reason='bad-txn-sigops') | ||||
# Rewind bad block | # Rewind bad block | ||||
tip(30) | tip(30) | ||||
# Max sigops in one p2sh txn | # Max sigops in one p2sh txn | ||||
max_p2sh_sigops = CScript([OP_CHECKSIG] * (p2sh_sigops_limit)) | max_p2sh_sigops = CScript([OP_CHECKSIG] * (p2sh_sigops_limit)) | ||||
block(32, spend=out[23], block_size=ONE_MEGABYTE + 1) | block(32, spend=out[8], block_size=ONE_MEGABYTE + 1) | ||||
update_block(32, [spend_p2sh_tx(max_p2sh_sigops)]) | update_block(32, [spend_p2sh_tx(max_p2sh_sigops)]) | ||||
node.p2p.send_blocks_and_test([self.tip], node) | node.p2p.send_blocks_and_test([self.tip], node) | ||||
# Submit a very large block via RPC | |||||
large_block = block( | |||||
33, spend=out[24], block_size=self.excessive_block_size) | |||||
node.submitblock(ToHex(large_block)) | |||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
FullBlockTest().main() | FullBlockTest().main() |