diff --git a/test/functional/abc-p2p-fullblocktest.py b/test/functional/abc-p2p-fullblocktest.py
--- a/test/functional/abc-p2p-fullblocktest.py
+++ b/test/functional/abc-p2p-fullblocktest.py
@@ -20,6 +20,7 @@
 from test_framework.script import *
 from test_framework.cdefs import (ONE_MEGABYTE, LEGACY_MAX_BLOCK_SIZE,
                                   MAX_BLOCK_SIGOPS_PER_MB, MAX_TX_SIGOPS_COUNT)
+from collections import deque
 
 
 class PreviousSpendableOutput():
@@ -70,12 +71,9 @@
         self.num_nodes = 1
         self.setup_clean_chain = True
         self.block_heights = {}
-        self.coinbase_key = CECKey()
-        self.coinbase_key.set_secretbytes(b"fatstacks")
-        self.coinbase_pubkey = self.coinbase_key.get_pubkey()
         self.tip = None
         self.blocks = {}
-        self.excessive_block_size = 64 * ONE_MEGABYTE
+        self.excessive_block_size = 100 * ONE_MEGABYTE
         self.extra_args = [['-norelaypriority',
                             '-whitelist=127.0.0.1',
                             '-limitancestorcount=9999',
@@ -109,31 +107,7 @@
         tx = create_transaction(spend_tx, n, b"", value, script)
         return tx
 
-    # sign a transaction, using the key we know about
-    # this signs input 0 in tx, which is assumed to be spending output n in
-    # spend_tx
-    def sign_tx(self, tx, spend_tx, n):
-        scriptPubKey = bytearray(spend_tx.vout[n].scriptPubKey)
-        if (scriptPubKey[0] == OP_TRUE):  # an anyone-can-spend
-            tx.vin[0].scriptSig = CScript()
-            return
-        sighash = SignatureHashForkId(
-            spend_tx.vout[n].scriptPubKey, tx, 0, SIGHASH_ALL | SIGHASH_FORKID, spend_tx.vout[n].nValue)
-        tx.vin[0].scriptSig = CScript(
-            [self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))])
-
-    def create_and_sign_transaction(self, spend_tx, n, value, script=CScript([OP_TRUE])):
-        tx = self.create_tx(spend_tx, n, value, script)
-        self.sign_tx(tx, spend_tx, n)
-        tx.rehash()
-        return tx
-
-    def next_block(self, number, spend=None, additional_coinbase_value=0, script=None, extra_sigops=0, block_size=0, solve=True):
-        """
-        Create a block on top of self.tip, and advance self.tip to point to the new block
-        if spend is specified, then 1 satoshi will be spent from that to an anyone-can-spend
-        output, and rest will go to fees.
-        """
+    def next_block(self, number, spend=None, script=CScript([OP_TRUE]), block_size=0, extra_sigops=0):
         if self.tip == None:
             base_block_hash = self.genesis_hash
             block_time = int(time.time()) + 1
@@ -142,70 +116,90 @@
             block_time = self.tip.nTime + 1
         # First create the coinbase
         height = self.block_heights[base_block_hash] + 1
-        coinbase = create_coinbase(height, self.coinbase_pubkey)
-        coinbase.vout[0].nValue += additional_coinbase_value
-        if (spend != None):
-            coinbase.vout[0].nValue += spend.tx.vout[
-                spend.n].nValue - 1  # all but one satoshi to fees
+        coinbase = create_coinbase(height)
         coinbase.rehash()
-        block = create_block(base_block_hash, coinbase, block_time)
-        spendable_output = None
-        if (spend != None):
+        if spend == None:
+            # We need to have something to spend to fill the block.
+            assert_equal(block_size, 0)
+            block = create_block(base_block_hash, coinbase, block_time)
+        else:
+            # all but one satoshi to fees
+            coinbase.vout[0].nValue += spend.tx.vout[spend.n].nValue - 1
+            coinbase.rehash()
+            block = create_block(base_block_hash, coinbase, block_time)
+            # spend 1 satoshi
             tx = CTransaction()
-            # no signature yet
-            tx.vin.append(
-                CTxIn(COutPoint(spend.tx.sha256, spend.n), b"", 0xffffffff))
-            # We put some random data into the first transaction of the chain
-            # to randomize ids
-            tx.vout.append(
-                CTxOut(0, CScript([random.randint(0, 255), OP_DROP, OP_TRUE])))
-            if script == None:
-                tx.vout.append(CTxOut(1, CScript([OP_TRUE])))
-            else:
+            tx.vin.append(CTxIn(COutPoint(spend.tx.sha256, spend.n)))
+            # Make sure we have plenty engough to spend going forward.
+            spendable_outputs = deque([])
+
+            def add_spendable_outputs(tx):
+                for i in range(8):
+                    tx.vout.append(CTxOut(0, CScript([OP_TRUE])))
+                    spendable_outputs.append(PreviousSpendableOutput(tx, i))
+            add_spendable_outputs(tx)
+
+            # Make it the same format as transaction added for padding and save the size.
+            # It's missing the padding output, so we add a constant to account for it.
+            tx.rehash()
+            base_tx_size = len(tx.serialize()) + 18
+
+            # If a specific script is required, add it.
+            if script != None:
                 tx.vout.append(CTxOut(1, script))
-            spendable_output = PreviousSpendableOutput(tx, 0)
 
-            # Now sign it if necessary
-            scriptSig = b""
-            scriptPubKey = bytearray(spend.tx.vout[spend.n].scriptPubKey)
-            if (scriptPubKey[0] == OP_TRUE):  # looks like an anyone-can-spend
-                scriptSig = CScript([OP_TRUE])
-            else:
-                # We have to actually sign it
-                sighash = SignatureHashForkId(
-                    spend.tx.vout[spend.n].scriptPubKey, tx, 0, SIGHASH_ALL | SIGHASH_FORKID, spend.tx.vout[spend.n].nValue)
-                scriptSig = CScript(
-                    [self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))])
-            tx.vin[0].scriptSig = scriptSig
-            # Now add the transaction to the block
+            # Put some random data into the first transaction of the chain to randomize ids.
+            tx.vout.append(
+                CTxOut(0, CScript([random.randint(0, 256), OP_RETURN])))
+
+            # Add the transaction to the block
             self.add_transactions_to_block(block, [tx])
-            block.hashMerkleRoot = block.calc_merkle_root()
-        if spendable_output != None and block_size > 0:
-            while len(block.serialize()) < block_size:
+
+            # If we have a block size requirement, just fill
+            # the block until we get there
+            current_block_size = len(block.serialize())
+            while current_block_size < block_size:
+                # We will add a new transaction. That means the size of
+                # the field enumerating how many transaction go in the block
+                # may change.
+                current_block_size -= len(ser_compact_size(len(block.vtx)))
+                current_block_size += len(ser_compact_size(len(block.vtx) + 1))
+
+                # Create the new transaction
                 tx = CTransaction()
-                script_length = block_size - len(block.serialize()) - 79
+                # Spend from one of the spendable outputs
+                spend = spendable_outputs.popleft()
+                tx.vin.append(CTxIn(COutPoint(spend.tx.sha256, spend.n)))
+                # Add spendable outputs
+                add_spendable_outputs(tx)
+
+                # Add padding to fill the block.
+                script_length = block_size - current_block_size - base_tx_size
                 if script_length > 510000:
                     script_length = 500000
-                tx_sigops = min(
-                    extra_sigops, script_length, MAX_TX_SIGOPS_COUNT)
+                tx_sigops = min(extra_sigops, script_length,
+                                MAX_TX_SIGOPS_COUNT)
                 extra_sigops -= tx_sigops
                 script_pad_len = script_length - tx_sigops
                 script_output = CScript(
                     [b'\x00' * script_pad_len] + [OP_CHECKSIG] * tx_sigops)
-                tx.vout.append(CTxOut(0, CScript([OP_TRUE])))
                 tx.vout.append(CTxOut(0, script_output))
-                tx.vin.append(
-                    CTxIn(COutPoint(spendable_output.tx.sha256, spendable_output.n)))
-                spendable_output = PreviousSpendableOutput(tx, 0)
+
+                # Add the tx to the list of transactions to be included
+                # in the block.
                 self.add_transactions_to_block(block, [tx])
+                current_block_size += len(tx.serialize())
+
+            # Now that we added a bunch of transaction, we need to recompute
+            # the merkle root.
             block.hashMerkleRoot = block.calc_merkle_root()
-            # Make sure the math above worked out to produce the correct block size
-            # (the math will fail if there are too many transactions in the block)
+
+        # Check that the block size is what's expected
+        if block_size > 0:
             assert_equal(len(block.serialize()), block_size)
-            # Make sure all the requested sigops have been included
-            assert_equal(extra_sigops, 0)
-        if solve:
-            block.solve()
+
+        # Do PoW, which is cheap on regnet
+        block.solve()
         self.tip = block
         self.block_heights[block.sha256] = height
         assert number not in self.blocks
@@ -296,15 +290,13 @@
 
         # Accept many sigops
         lots_of_checksigs = CScript(
-            [OP_CHECKSIG] * (MAX_BLOCK_SIGOPS_PER_MB - 1))
-        block(
-            19, spend=out[17], script=lots_of_checksigs, block_size=ONE_MEGABYTE)
+            [OP_CHECKSIG] * MAX_BLOCK_SIGOPS_PER_MB)
+        block(19, spend=out[17], script=lots_of_checksigs,
+              block_size=ONE_MEGABYTE)
         yield accepted()
 
-        too_many_blk_checksigs = CScript(
-            [OP_CHECKSIG] * MAX_BLOCK_SIGOPS_PER_MB)
-        block(
-            20, spend=out[18], script=too_many_blk_checksigs, block_size=ONE_MEGABYTE)
+        block(20, spend=out[18], script=lots_of_checksigs,
+              block_size=ONE_MEGABYTE, extra_sigops=1)
         yield rejected(RejectResult(16, b'bad-blk-sigops'))
 
         # Rewind bad block
@@ -372,16 +364,20 @@
         # Rewind bad block
         tip(26)
 
+        # Generate a key pair to test P2SH sigops count
+        private_key = CECKey()
+        private_key.set_secretbytes(b"fatstacks")
+        public_pubkey = private_key.get_pubkey()
+
         # P2SH
         # Build the redeem script, hash it, use hash to create the p2sh script
-        redeem_script = CScript([self.coinbase_pubkey] + [
-                                OP_2DUP, OP_CHECKSIGVERIFY] * 5 + [OP_CHECKSIG])
+        redeem_script = CScript(
+            [public_pubkey] + [OP_2DUP, OP_CHECKSIGVERIFY] * 5 + [OP_CHECKSIG])
         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)
+        p2sh_tx = self.create_tx(out[22].tx, out[22].n, 1, p2sh_script)
 
         # Add the transaction to the block
         block(30)
@@ -398,8 +394,8 @@
             # Sign the transaction using the redeem script
             sighash = SignatureHashForkId(
                 redeem_script, spent_p2sh_tx, 0, SIGHASH_ALL | SIGHASH_FORKID, p2sh_tx.vout[0].nValue)
-            sig = self.coinbase_key.sign(sighash) + bytes(
-                bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
+            sig = private_key.sign(sighash) + \
+                bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
             spent_p2sh_tx.vin[0].scriptSig = CScript([sig, redeem_script])
             spent_p2sh_tx.rehash()
             return spent_p2sh_tx