diff --git a/qa/rpc-tests/abc-p2p-fullblocktest.py b/qa/rpc-tests/abc-p2p-fullblocktest.py --- a/qa/rpc-tests/abc-p2p-fullblocktest.py +++ b/qa/rpc-tests/abc-p2p-fullblocktest.py @@ -24,6 +24,13 @@ # far into the future UAHF_START_TIME = 2000000000 +#The maximum number of sigops we're willing to relay/mine in a single tx (policy.h) +MAX_STANDARD_TX_SIGOPS = MAX_TX_SIGOPS_COUNT // 5 + +# Error for too many sigops in one TX +TXNS_TOO_MANY_SIGOPS_ERROR = b'bad-txns-too-many-sigops' +RPC_TXNS_TOO_MANY_SIGOPS_ERROR = "64: " + TXNS_TOO_MANY_SIGOPS_ERROR.decode("utf-8") + class PreviousSpendableOutput(object): def __init__(self, tx = CTransaction(), n = -1): self.tx = tx @@ -250,6 +257,9 @@ # shorthand for functions block = self.next_block + # shorthand for variables + node = self.nodes[0] + # Create a new block block(0) save_spendable_output() @@ -375,19 +385,11 @@ redeem_script_hash = hash160(redeem_script) p2sh_script = CScript([OP_HASH160, redeem_script_hash, OP_EQUAL]) - # Create a p2sh transaction - p2sh_tx = self.create_and_sign_transaction(out[22].tx, out[22].n, 1, p2sh_script) - - # Add the transaction to the block - block(30) - update_block(30, [p2sh_tx]) - yield accepted() - - # Creates a new transaction using the p2sh transaction included in the last block - def spend_p2sh_tx (output_script=CScript([OP_TRUE])): + # Creates a new transaction using a p2sh transaction as input + def spend_p2sh_tx (p2sh_tx_to_spend, output_script=CScript([OP_TRUE])): # Create the transaction spent_p2sh_tx = CTransaction() - spent_p2sh_tx.vin.append(CTxIn(COutPoint(p2sh_tx.sha256, 0), b'')) + spent_p2sh_tx.vin.append(CTxIn(COutPoint(p2sh_tx_to_spend.sha256, 0), b'')) spent_p2sh_tx.vout.append(CTxOut(1, output_script)) # Sign the transaction using the redeem script (sighash, err) = SignatureHash(redeem_script, spent_p2sh_tx, 0, SIGHASH_ALL) @@ -396,12 +398,21 @@ spent_p2sh_tx.rehash() return spent_p2sh_tx - # Sigops p2sh limit + # P2SH block tests + # Create a p2sh transaction + p2sh_tx = self.create_and_sign_transaction(out[22].tx, out[22].n, 1, p2sh_script) + + # Add the transaction to the block + block(30) + update_block(30, [p2sh_tx]) + yield accepted() + + # Sigops p2sh limit for the block test p2sh_sigops_limit = MAX_BLOCK_SIGOPS_PER_MB - redeem_script.GetSigOpCount(True) # Too many sigops in one p2sh txn too_many_p2sh_sigops = CScript([OP_CHECKSIG] * (p2sh_sigops_limit + 1)) block(31, spend=out[23], block_size=ONE_MEGABYTE + 1) - update_block(31, [spend_p2sh_tx(too_many_p2sh_sigops)]) + update_block(31, [spend_p2sh_tx(p2sh_tx, too_many_p2sh_sigops)]) yield rejected(RejectResult(16, b'bad-txn-sigops')) # Rewind bad block @@ -410,11 +421,51 @@ # Max sigops in one p2sh txn max_p2sh_sigops = CScript([OP_CHECKSIG] * (p2sh_sigops_limit)) block(32, spend=out[23], block_size=ONE_MEGABYTE + 1) - update_block(32, [spend_p2sh_tx(max_p2sh_sigops)]) + update_block(32, [spend_p2sh_tx(p2sh_tx, max_p2sh_sigops)]) + yield accepted() + + # P2SH mempool tests + # Create a p2sh transaction + p2sh_tx_mempool = self.create_and_sign_transaction(out[24].tx, out[24].n, 1, p2sh_script) + + # Add the transaction to the block + block(33) + update_block(33, [p2sh_tx_mempool]) + yield accepted() + + # Sigops p2sh limit for the mempool test + p2sh_sigops_limit_mempool = MAX_STANDARD_TX_SIGOPS - redeem_script.GetSigOpCount(True) + # Too many sigops in one p2sh script + too_many_p2sh_sigops_mempool = CScript([OP_CHECKSIG] * (p2sh_sigops_limit_mempool + 1)) + + # A transaction with this output script can't get into the mempool + try: + node.sendrawtransaction(ToHex(spend_p2sh_tx(p2sh_tx_mempool, too_many_p2sh_sigops_mempool))) + except JSONRPCException as exp: + assert_equal(exp.error["message"], RPC_TXNS_TOO_MANY_SIGOPS_ERROR) + else: + assert(False) + + # The transaction is rejected, so the mempool should still be empty + assert_equal(set(node.getrawmempool()), set()) + + # Max sigops in one p2sh txn + max_p2sh_sigops_mempool = CScript([OP_CHECKSIG] * (p2sh_sigops_limit_mempool)) + + # A transaction with this output script can get into the mempool + max_p2sh_sigops_txn = spend_p2sh_tx(p2sh_tx_mempool, max_p2sh_sigops_mempool) + max_p2sh_sigops_txn_id = node.sendrawtransaction(ToHex(max_p2sh_sigops_txn)) + assert_equal(set(node.getrawmempool()), {max_p2sh_sigops_txn_id}) + + # Mine the transaction + block(34, spend=out[25], block_size=ONE_MEGABYTE + 1) + update_block(34, [max_p2sh_sigops_txn]) yield accepted() + # The transaction has been mined, it's not in the mempool anymore + assert_equal(set(node.getrawmempool()), set()) + # Check that compact block also work for big blocks - node = self.nodes[0] peer = TestNode() peer.add_connection(NodeConn('127.0.0.1', p2p_port(0), node, peer)); @@ -453,7 +504,7 @@ peer.send_message(peer.last_headers) # Send a block - b33 = block(33, spend=out[24], block_size=ONE_MEGABYTE + 1) + b35 = block(35, spend=out[26], block_size=ONE_MEGABYTE + 1) yield accepted() # Checks the node to forward it via compact block @@ -465,11 +516,11 @@ # Was it our block ? cmpctblk_header = peer.last_cmpctblock.header_and_shortids.header cmpctblk_header.calc_sha256() - assert(cmpctblk_header.sha256 == b33.sha256) + assert(cmpctblk_header.sha256 == b35.sha256) # Send a bigger block peer.clear_block_data() - b34 = block(34, spend=out[25], block_size=8*ONE_MEGABYTE) + b36 = block(36, spend=out[27], block_size=8*ONE_MEGABYTE) yield accepted() # Checks the node to forward it via compact block @@ -479,22 +530,22 @@ # Was it our block ? cmpctblk_header = peer.last_cmpctblock.header_and_shortids.header cmpctblk_header.calc_sha256() - assert(cmpctblk_header.sha256 == b34.sha256) + assert(cmpctblk_header.sha256 == b36.sha256) # Let's send a compact block and see if the node accepts it. # First, we generate the block and send all transaction to the mempool - b35 = block(35, spend=out[26], block_size=8*ONE_MEGABYTE) - for i in range(1, len(b35.vtx)): - node.sendrawtransaction(ToHex(b35.vtx[i]), True) + b37 = block(37, spend=out[28], block_size=8*ONE_MEGABYTE) + for i in range(1, len(b37.vtx)): + node.sendrawtransaction(ToHex(b37.vtx[i]), True) # Now we create the compact block and send it comp_block = HeaderAndShortIDs() - comp_block.initialize_from_block(b35) + comp_block.initialize_from_block(b37) peer.send_and_ping(msg_cmpctblock(comp_block.to_p2p())) # Check that compact block is received properly - assert(int(node.getbestblockhash(), 16) == b35.sha256) + assert(int(node.getbestblockhash(), 16) == b37.sha256) if __name__ == '__main__': - FullBlockTest().main() + FullBlockTest().main() \ No newline at end of file