def create_fund_and_spend_tx():
            spendfrom = spendable_outputs.pop()

            script = CScript([OP_ADD])

            value = spendfrom.vout[0].nValue

            # Fund transaction
            txfund = create_transaction(spendfrom, 0, b'', value, script)
            pad_tx(txfund)
            txfund.rehash()
            fundings.append(txfund)

            # Spend transaction
            txspend = CTransaction()
            txspend.vout.append(CTxOut(value - 1000, CScript([OP_TRUE])))
            txspend.vin.append(CTxIn(COutPoint(txfund.sha256, 0), b''))

            # Sign the transaction
            txspend.vin[0].scriptSig = CScript(
                b'\x01\x01\x51')  # PUSH1(0x01) OP_1
            pad_tx(txspend)
            txspend.rehash()

            return txspend
        def create_fund_and_spend_tx(dummy=OP_0, sigtype='ecdsa'):
            spendfrom = spendable_outputs.pop()

            script = CScript([OP_1, public_key, OP_1, OP_CHECKMULTISIG])

            value = spendfrom.vout[0].nValue

            # Fund transaction
            txfund = create_transaction(spendfrom, 0, b'', value, script)
            txfund.rehash()
            fundings.append(txfund)

            # Spend transaction
            txspend = CTransaction()
            txspend.vout.append(CTxOut(value - 1000, CScript([OP_TRUE])))
            txspend.vin.append(CTxIn(COutPoint(txfund.sha256, 0), b''))

            # Sign the transaction
            sighashtype = SIGHASH_ALL | SIGHASH_FORKID
            hashbyte = bytes([sighashtype & 0xff])
            sighash = SignatureHashForkId(script, txspend, 0, sighashtype,
                                          value)
            if sigtype == 'schnorr':
                txsig = schnorr.sign(privkeybytes, sighash) + hashbyte
            elif sigtype == 'ecdsa':
                txsig = private_key.sign(sighash) + hashbyte
            txspend.vin[0].scriptSig = CScript([dummy, txsig])
            txspend.rehash()

            return txspend
示例#3
0
    def test_invalid_args(self, electrum_client):
        from test_framework.connectrum.exc import ElectrumErrorResponse
        error_code = "-32602"

        hash_param_methods = ("blockchain.scripthash.get_balance",
                              "blockchain.scripthash.get_history",
                              "blockchain.scripthash.listunspent")

        for method in hash_param_methods:
            assert_raises(ElectrumErrorResponse, electrum_client.call, method,
                          "invalidhash")

            try:
                electrum_client.call(method, "invalidhash")
            except Exception as e:
                print("ERROR:" + str(e))
                assert error_code in str(e)

        # invalid tx
        try:
            tx = CTransaction()
            tx.calc_sha256()
            tx.vin = [CTxIn(COutPoint(0xbeef, 1))]
            electrum_client.call("blockchain.transaction.broadcast", ToHex(tx))
        except Exception as e:
            print("ERROR: " + str(e))
            assert error_code in str(e)
示例#4
0
        def create_segwit_fund_and_spend_tx(spend, case0=False):
            if not case0:
                # Spending from a P2SH-P2WPKH coin,
                #   txhash:a45698363249312f8d3d93676aa714be59b0bd758e62fa054fb1ea6218480691
                redeem_script0 = bytearray.fromhex(
                    '0014fcf9969ce1c98a135ed293719721fb69f0b686cb')
                # Spending from a P2SH-P2WSH coin,
                #   txhash:6b536caf727ccd02c395a1d00b752098ec96e8ec46c96bee8582be6b5060fa2f
                redeem_script1 = bytearray.fromhex(
                    '0020fc8b08ed636cb23afcb425ff260b3abd03380a2333b54cfa5d51ac52d803baf4'
                )
            else:
                redeem_script0 = bytearray.fromhex('51020000')
                redeem_script1 = bytearray.fromhex('53020080')
            redeem_scripts = [redeem_script0, redeem_script1]

            # Fund transaction to segwit addresses
            txfund = CTransaction()
            txfund.vin = [CTxIn(COutPoint(spend.tx.sha256, spend.n))]
            amount = (50 * COIN - 1000) // len(redeem_scripts)
            for redeem_script in redeem_scripts:
                txfund.vout.append(
                    CTxOut(
                        amount,
                        CScript([OP_HASH160,
                                 hash160(redeem_script), OP_EQUAL])))
            txfund.rehash()

            # Segwit spending transaction
            # We'll test if a node that checks for standardness accepts this
            # txn. It should fail exclusively because of the restriction in
            # the scriptSig (non clean stack..), so all other characteristcs
            # must pass standardness checks. For this reason, we create
            # standard P2SH outputs.
            txspend = CTransaction()
            for i in range(len(redeem_scripts)):
                txspend.vin.append(
                    CTxIn(COutPoint(txfund.sha256, i),
                          CScript([redeem_scripts[i]])))
            txspend.vout = [
                CTxOut(
                    50 * COIN - 2000,
                    CScript(
                        [OP_HASH160,
                         hash160(CScript([OP_TRUE])), OP_EQUAL]))
            ]
            txspend.rehash()

            return txfund, txspend
        def make_spend(sigcheckcount):
            # Add a funding tx to fundings, and return a tx spending that using
            # scriptsig.
            logging.debug("Gen tx with {} sigchecks.".format(sigcheckcount))

            def get_script_with_sigcheck(count):
                return CScript([cds_message, cds_pubkey] +
                               (count - 1) * [OP_3DUP, OP_CHECKDATASIGVERIFY] +
                               [OP_CHECKDATASIG])

            # get funds locked with OP_1
            sourcetx = self.spendable_outputs.popleft()
            # make funding that forwards to scriptpubkey
            last_sigcheck_count = ((sigcheckcount - 1) % 30) + 1
            fundtx = create_transaction(
                sourcetx, get_script_with_sigcheck(last_sigcheck_count))

            fill_sigcheck_script = get_script_with_sigcheck(30)

            remaining_sigcheck = sigcheckcount
            while remaining_sigcheck > 30:
                fundtx.vout[0].nValue -= 1000
                fundtx.vout.append(CTxOut(100, bytes(fill_sigcheck_script)))
                remaining_sigcheck -= 30

            fundtx.rehash()
            fundings.append(fundtx)

            # make the spending
            scriptsig = CScript([cds_signature])

            tx = CTransaction()
            tx.vin.append(CTxIn(COutPoint(fundtx.sha256, 1), scriptsig))

            input_index = 2
            remaining_sigcheck = sigcheckcount
            while remaining_sigcheck > 30:
                tx.vin.append(
                    CTxIn(COutPoint(fundtx.sha256, input_index), scriptsig))
                remaining_sigcheck -= 30
                input_index += 1

            tx.vout.append(CTxOut(0, CScript([OP_RETURN])))
            pad_tx(tx)
            tx.rehash()
            return tx
        def make_spend(scriptpubkey, scriptsig):
            # Add a funding tx to fundings, and return a tx spending that using
            # scriptsig.
            logging.debug(
                "Gen tx with locking script {} unlocking script {} .".format(
                    scriptpubkey.hex(), scriptsig.hex()))

            # get funds locked with OP_1
            sourcetx = self.spendable_outputs.popleft()
            # make funding that forwards to scriptpubkey
            fundtx = create_transaction(sourcetx, scriptpubkey)
            fundings.append(fundtx)

            # make the spending
            tx = CTransaction()
            tx.vin.append(CTxIn(COutPoint(fundtx.sha256, 1), scriptsig))
            tx.vout.append(CTxOut(0, CScript([OP_RETURN])))
            pad_tx(tx)
            tx.rehash()
            return tx
def create_transaction(spendfrom, custom_script, amount=None):
    # Fund and sign a transaction to a given output.
    # spendfrom should be a CTransaction with first output to OP_TRUE.

    # custom output will go on position 1, after position 0 which will be
    # OP_TRUE (so it can be reused).
    customout = CTxOut(0, bytes(custom_script))
    # set output amount to required dust if not given
    customout.nValue = amount or (len(customout.serialize()) + 148) * 3

    ctx = CTransaction()
    ctx.vin.append(CTxIn(COutPoint(spendfrom.sha256, 0), bytes([OP_TRUE])))
    ctx.vout.append(CTxOut(0, bytes([OP_TRUE])))
    ctx.vout.append(customout)
    pad_tx(ctx)

    fee = len(ctx.serialize())
    ctx.vout[0].nValue = spendfrom.vout[0].nValue - customout.nValue - fee
    ctx.rehash()

    return ctx
示例#8
0
        def create_fund_and_spend_tx():
            spend_from = spendable_outputs.pop()
            value = spend_from.vout[0].nValue

            # Reversed data
            data = bytes.fromhex('0123456789abcdef')
            rev_data = bytes(reversed(data))

            # Lockscript: provide a bytestring that reverses to X
            script = CScript([OP_REVERSEBYTES, rev_data, OP_EQUAL])

            # Fund transaction: REVERSEBYTES <reversed(x)> EQUAL
            tx_fund = create_tx_with_script(spend_from, 0, b'', value, script)
            tx_fund.rehash()

            # Spend transaction: <x>
            tx_spend = CTransaction()
            tx_spend.vout.append(
                CTxOut(value - 1000, CScript([b'x' * 100, OP_RETURN])))
            tx_spend.vin.append(CTxIn(COutPoint(tx_fund.sha256, 0), b''))
            tx_spend.vin[0].scriptSig = CScript([data])
            tx_spend.rehash()

            return tx_spend, tx_fund
    def create_cashaccount_tx(self, n, spend, name, address):
        fee = 500
        tx = create_transaction(
            FromHex(CTransaction(), n.getrawtransaction(spend['txid'])),
            spend['vout'], b"", spend['satoshi'] - fee)

        _, _, keyhash = decode_addr(address)

        name = bytes(name, 'ascii')
        keyhash = DATATYPE_KEYHASH + keyhash

        cashaccount_script = CScript(
            [OP_RETURN, CASHACCONT_PREFIX, name, keyhash])

        tx.vout.append(CTxOut(0, cashaccount_script))
        tx.rehash()
        return n.signrawtransaction(ToHex(tx))['hex']
 def __init__(self, tx=CTransaction(), n=-1):
     self.tx = tx
     self.n = n
    def run_test(self):
        logging.info("Initializing test directory "+self.options.tmpdir)
        node = self.nodes[0]

        self.bootstrap_p2p()

        tip = self.get_best_block(node)

        logging.info("Create some blocks with OP_1 coinbase for spending.")
        blocks = []
        for _ in range(10):
            tip = self.build_block(tip)
            blocks.append(tip)
        self.p2p.send_blocks_and_test(blocks, node, success=True)
        spendable_outputs = [block.vtx[0] for block in blocks]

        logging.info("Mature the blocks and get out of IBD.")
        node.generate(100)

        tip = self.get_best_block(node)

        logging.info(
            "Set up spending transactions to test and mine the funding transactions.")

        # Generate a key pair
        privkeybytes = b"xyzxyzhh" * 4
        private_key = CECKey()
        private_key.set_secretbytes(privkeybytes)
        # get uncompressed public key serialization
        public_key = private_key.get_pubkey()

        # Create funding/spending transaction pair
        spend_from = spendable_outputs.pop()
        value = spend_from.vout[0].nValue

        # Reversed data
        data = bytes.fromhex('0123456789abcdef')
        rev_data = bytes(reversed(data))

        # Lockscript: provide a bytestring that reverses to X
        script = CScript([OP_REVERSEBYTES, rev_data, OP_EQUAL])

        # Fund transaction: REVERSEBYTES <reversed(x)> EQUAL
        tx_reversebytes_fund = create_tx_with_script(spend_from, 0, b'', value, script)
        tx_reversebytes_fund.rehash()

        # Spend transaction: <x>
        tx_reversebytes_spend = CTransaction()
        tx_reversebytes_spend.vout.append(CTxOut(value - 1000, CScript([b'x' * 100, OP_RETURN])))
        tx_reversebytes_spend.vin.append(CTxIn(COutPoint(tx_reversebytes_fund.sha256, 0), b''))
        tx_reversebytes_spend.vin[0].scriptSig = CScript([data])
        tx_reversebytes_spend.rehash()

        # Mine funding transaction into block. Pre-upgrade output scripts can have
        # OP_REVERSEBYTES and still be fully valid, but they cannot spend it.
        tip = self.build_block(tip, [tx_reversebytes_fund])
        self.p2p.send_blocks_and_test([tip], node)

        logging.info(
            "Submitting a new OP_REVERSEBYTES tx via net, and mining it in a block")
        # Send OP_REVERSEBYTES tx
        self.p2p.send_txs_and_test([tx_reversebytes_spend], node)

        # Verify OP_REVERSEBYTES tx is in mempool
        waitFor(10, lambda: set(node.getrawmempool()) == {tx_reversebytes_spend.hash})

        # Mine OP_REVERSEBYTES tx into block
        tip = self.build_block(tip, [tx_reversebytes_spend])
        self.p2p.send_blocks_and_test([tip], node)
示例#12
0
    def _zmq_test(self):
        """Note that this function is very picky about the exact order of generated ZMQ announcements.
           However, this order does not actually matter.  So bitcoind code changes my break this test.
        """
        num_blocks = 5
        logging.info(
            "Generate {0} blocks (and {0} coinbase txes)".format(num_blocks))

        # DS does not support P2PK so make sure there's a P2PKH in the wallet
        addr = self.nodes[0].getnewaddress()
        fundTx = self.nodes[0].sendtoaddress(addr, 10)
        # Notify of new tx
        zmqNotif = self.hashtx.receive().hex()
        assert fundTx == zmqNotif
        zmqNotif = self.rawtx.receive()

        genhashes = self.nodes[0].generate(1)
        # notify tx 1
        zmqNotif1 = self.hashtx.receive().hex()
        assert fundTx == zmqNotif1
        zmqNotif1r = self.rawtx.receive()
        # notify coinbase
        zmqNotif2 = self.hashtx.receive().hex()
        zmqNotif2r = self.rawtx.receive()
        assert b"/EB32/AD12" in zmqNotif2r
        # notify tx 1 again
        zmqNotif = self.hashtx.receive().hex()
        assert fundTx == zmqNotif
        zmqNotif = self.rawtx.receive()

        # notify the block
        h = self.hashblock.receive().hex()
        b = self.rawblock.receive()

        genhashes = self.nodes[0].generate(num_blocks)

        self.sync_all()

        for x in range(num_blocks):
            # Should receive the coinbase txid.
            txid = self.hashtx.receive()
            # Should receive the coinbase raw transaction.
            hex = self.rawtx.receive()
            tx = CTransaction()
            tx.deserialize(BytesIO(hex))
            tx.calc_sha256()
            assert_equal(tx.hash, txid.hex())


            # Should receive the generated block hash.
            hash = self.hashblock.receive().hex()
            assert_equal(genhashes[x], hash)
            # The block should only have the coinbase txid.
            assert_equal([txid.hex()], self.nodes[1].getblock(hash)["tx"])

            # Should receive the generated raw block.
            block = self.rawblock.receive()
            assert_equal(genhashes[x], hash256(block[:80])[::-1].hex())

        logging.info("Wait for tx from second node")
        payment_txid = self.nodes[1].sendtoaddress(
            self.nodes[0].getnewaddress(), 1.0)
        self.sync_all()

        # Should receive the broadcasted txid.
        txid = self.hashtx.receive()
        assert_equal(payment_txid, txid.hex())

        # Should receive the broadcasted raw transaction.
        hex = self.rawtx.receive()
        assert_equal(payment_txid, hash256(hex)[::-1].hex())

        if 1: # Send 2 transactions that double spend each other

            # If these unsubscribes fail, then you will get an assertion that a zmq topic is not correct
            self.hashtx.unsubscribe()
            self.rawtx.unsubscribe()

            wallet = self.nodes[0].listunspent()
            walletp2pkh = list(filter(lambda x : len(x["scriptPubKey"]) != 70, wallet)) # Find an input that is not P2PK
            t = walletp2pkh.pop()
            inputs = []
            inputs.append({ "txid" : t["txid"], "vout" : t["vout"]})
            outputs = { self.nodes[1].getnewaddress() : t["amount"] }

            rawtx   = self.nodes[0].createrawtransaction(inputs, outputs)
            rawtx   = self.nodes[0].signrawtransaction(rawtx)
            mpTx = self.nodes[0].getmempoolinfo()["size"]
            try:
                hashTxToDoubleSpend   = self.nodes[1].sendrawtransaction(rawtx['hex'])
            except JSONRPCException as e:
                print(e.error['message'])
                assert False
                self.sync_all()

            outputs = { self.nodes[1].getnewaddress() : t["amount"] }
            rawtx   = self.nodes[0].createrawtransaction(inputs, outputs)
            rawtx   = self.nodes[0].signrawtransaction(rawtx)
            waitFor(30, lambda: self.nodes[0].getmempoolinfo()["size"] > mpTx)  # make sure the original tx propagated in time
            try:
                hashtx   = self.nodes[0].sendrawtransaction(rawtx['hex'])
            except JSONRPCException as e:
                assert("txn-mempool-conflict" in e.error['message'])
            else:
                assert(False)
                self.sync_all()

            # since I unsubscribed from these I don't need to load them
            #self.hashtx.receive()
            #self.rawtx.receive()

            # Should receive hash of a double spend proof.
            dsTxHash = self.hashds.receive()
            assert hashTxToDoubleSpend == dsTxHash.hex()
            ds  = self.rawds.receive()
            assert len(ds) > 0
    def run_test(self):
        node = self.nodes[0]
        self.pynode = P2PDataStore()
        self.connection = NodeConn('127.0.0.1', p2p_port(0), node, self.pynode)
        self.pynode.add_connection(self.connection)
        NetworkThread().start()
        self.pynode.wait_for_verack()

        # Get out of IBD
        node.generate(1)

        tip = self.getbestblock(node)

        logging.info("Create some blocks with OP_1 coinbase for spending.")
        blocks = []
        for _ in range(20):
            tip = self.build_block(tip)
            blocks.append(tip)
        self.pynode.send_blocks_and_test(blocks, node, success=True)
        self.spendable_outputs = deque(block.vtx[0] for block in blocks)

        logging.info("Mature the blocks.")
        node.generate(100)

        tip = self.getbestblock(node)

        # To make compact and fast-to-verify transactions, we'll use
        # CHECKDATASIG over and over with the same data.
        # (Using the same stuff over and over again means we get to hit the
        # node's signature cache and don't need to make new signatures every
        # time.)
        cds_message = b''
        # r=1 and s=1 ecdsa, the minimum values.
        cds_signature = bytes.fromhex('3006020101020101')
        # Recovered pubkey
        cds_pubkey = bytes.fromhex(
            '03089b476b570d66fad5a20ae6188ebbaf793a4c2a228c65f3d79ee8111d56c932'
        )

        def minefunding2(n):
            """ Mine a block with a bunch of outputs that are very dense
            sigchecks when spent (2 sigchecks each); return the inputs that can
            be used to spend. """
            cds_scriptpubkey = CScript([
                cds_message, cds_pubkey, OP_3DUP, OP_CHECKDATASIGVERIFY,
                OP_CHECKDATASIGVERIFY
            ])
            # The scriptsig is carefully padded to have size 26, which is the
            # shortest allowed for 2 sigchecks for mempool admission.
            # The resulting inputs have size 67 bytes, 33.5 bytes/sigcheck.
            cds_scriptsig = CScript([b'x' * 16, cds_signature])
            assert_equal(len(cds_scriptsig), 26)

            logging.debug(
                "Gen {} with locking script {} unlocking script {} .".format(
                    n, cds_scriptpubkey.hex(), cds_scriptsig.hex()))

            tx = self.spendable_outputs.popleft()
            usable_inputs = []
            txes = []
            for i in range(n):
                tx = create_transaction(tx, cds_scriptpubkey,
                                        bytes([OP_TRUE]) if i == 0 else b"")
                txes.append(tx)
                usable_inputs.append(
                    CTxIn(COutPoint(tx.sha256, 1), cds_scriptsig))
            newtip = self.build_block(tip, txes)
            self.pynode.send_blocks_and_test([newtip], node, timeout=10)
            return usable_inputs, newtip

        logging.info("Funding special coins that have high sigchecks")

        # mine 5000 funded outputs (10000 sigchecks)
        # will be used pre-activation and post-activation
        usable_inputs, tip = minefunding2(5000)
        # assemble them into 50 txes with 100 inputs each (200 sigchecks)
        submittxes_1 = []
        while len(usable_inputs) >= 100:
            tx = CTransaction()
            tx.vin = [usable_inputs.pop() for _ in range(100)]
            tx.vout = [CTxOut(0, CScript([OP_RETURN]))]
            tx.rehash()
            submittxes_1.append(tx)

        # mine 5000 funded outputs (10000 sigchecks)
        # will be used post-activation
        usable_inputs, tip = minefunding2(5000)
        # assemble them into 50 txes with 100 inputs each (200 sigchecks)
        submittxes_2 = []
        while len(usable_inputs) >= 100:
            tx = CTransaction()
            tx.vin = [usable_inputs.pop() for _ in range(100)]
            tx.vout = [CTxOut(0, CScript([OP_RETURN]))]
            tx.rehash()
            submittxes_2.append(tx)

        # Check high sigcheck transactions
        logging.info("Create transaction that have high sigchecks")

        fundings = []

        def make_spend(sigcheckcount):
            # Add a funding tx to fundings, and return a tx spending that using
            # scriptsig.
            logging.debug("Gen tx with {} sigchecks.".format(sigcheckcount))

            def get_script_with_sigcheck(count):
                return CScript([cds_message, cds_pubkey] +
                               (count - 1) * [OP_3DUP, OP_CHECKDATASIGVERIFY] +
                               [OP_CHECKDATASIG])

            # get funds locked with OP_1
            sourcetx = self.spendable_outputs.popleft()
            # make funding that forwards to scriptpubkey
            last_sigcheck_count = ((sigcheckcount - 1) % 30) + 1
            fundtx = create_transaction(
                sourcetx, get_script_with_sigcheck(last_sigcheck_count))

            fill_sigcheck_script = get_script_with_sigcheck(30)

            remaining_sigcheck = sigcheckcount
            while remaining_sigcheck > 30:
                fundtx.vout[0].nValue -= 1000
                fundtx.vout.append(CTxOut(100, bytes(fill_sigcheck_script)))
                remaining_sigcheck -= 30

            fundtx.rehash()
            fundings.append(fundtx)

            # make the spending
            scriptsig = CScript([cds_signature])

            tx = CTransaction()
            tx.vin.append(CTxIn(COutPoint(fundtx.sha256, 1), scriptsig))

            input_index = 2
            remaining_sigcheck = sigcheckcount
            while remaining_sigcheck > 30:
                tx.vin.append(
                    CTxIn(COutPoint(fundtx.sha256, input_index), scriptsig))
                remaining_sigcheck -= 30
                input_index += 1

            tx.vout.append(CTxOut(0, CScript([OP_RETURN])))
            pad_tx(tx)
            tx.rehash()
            return tx

        # Create transactions with many sigchecks.
        good_tx = make_spend(MAX_TX_SIGCHECK)
        bad_tx = make_spend(MAX_TX_SIGCHECK + 1)
        tip = self.build_block(tip, fundings)
        self.pynode.send_blocks_and_test([tip], node)

        # Both tx are accepted before the activation.
        pre_activation_sigcheck_block = self.build_block(
            tip, [good_tx, bad_tx])
        self.pynode.send_blocks_and_test([pre_activation_sigcheck_block], node)
        node.invalidateblock(pre_activation_sigcheck_block.hash)

        # after block is invalidated these tx are put back into the mempool.  Test uses them later so evict.
        waitFor(10, lambda: node.getmempoolinfo()["size"] == 2)
        node.evicttransaction(good_tx.hash)
        node.evicttransaction(bad_tx.hash)

        # Activation tests

        logging.info("Approach to just before upgrade activation")
        # Move our clock to the uprade time so we will accept such
        # future-timestamped blocks.
        node.setmocktime(SIGCHECKS_ACTIVATION_TIME + 10)
        # Mine six blocks with timestamp starting at
        # SIGCHECKS_ACTIVATION_TIME-1
        blocks = []
        for i in range(-1, 5):
            tip = self.build_block(tip, nTime=SIGCHECKS_ACTIVATION_TIME + i)
            blocks.append(tip)
        self.pynode.send_blocks_and_test(blocks, node, timeout=TIMEOUT)
        assert_equal(node.getblockchaininfo()['mediantime'],
                     SIGCHECKS_ACTIVATION_TIME - 1)

        logging.info(
            "The next block will activate, but the activation block itself must follow old rules"
        )
        # Send the 50 txes and get the node to mine as many as possible (it should do all)
        # The node is happy mining and validating a 10000 sigcheck block before
        # activation.
        self.pynode.send_txs_and_test(submittxes_1, node, timeout=TIMEOUT)
        [blockhash] = node.generate(1)
        assert_equal(set(node.getblock(blockhash, 1)["tx"][1:]),
                     {t.hash
                      for t in submittxes_1})

        # We have activated, but let's invalidate that.
        assert_equal(node.getblockchaininfo()['mediantime'],
                     SIGCHECKS_ACTIVATION_TIME)
        node.invalidateblock(blockhash)

        # Try again manually and invalidate that too
        goodblock = self.build_block(tip, submittxes_1)
        self.pynode.send_blocks_and_test([goodblock], node, timeout=TIMEOUT)
        node.invalidateblock(goodblock.hash)
        # All transactions should be back in mempool: validation is very slow in debug build
        waitFor(
            60, lambda: set(node.getrawmempool()) ==
            {t.hash
             for t in submittxes_1})

        logging.info("Mine the activation block itself")
        tip = self.build_block(tip)
        self.pynode.send_blocks_and_test([tip], node, timeout=TIMEOUT)

        logging.info("We have activated!")
        assert_equal(node.getblockchaininfo()['mediantime'],
                     SIGCHECKS_ACTIVATION_TIME)

        # All transactions get re-evaluated to count sigchecks, so wait for them
        waitFor(
            60, lambda: set(node.getrawmempool()) ==
            {t.hash
             for t in submittxes_1})

        logging.info(
            "Try a block with a transaction going over the limit (limit: {})".
            format(MAX_TX_SIGCHECK))
        bad_tx_block = self.build_block(tip, [bad_tx])
        check_for_ban_on_rejected_block(
            self.pynode,
            node,
            bad_tx_block,
            reject_reason=BLOCK_SIGCHECKS_BAD_TX_SIGCHECKS)

        logging.info(
            "Try a block with a transaction just under the limit (limit: {})".
            format(MAX_TX_SIGCHECK))
        good_tx_block = self.build_block(tip, [good_tx])
        self.pynode.send_blocks_and_test([good_tx_block],
                                         node,
                                         timeout=TIMEOUT)
        node.invalidateblock(good_tx_block.hash)

        # save this tip for later
        # ~ upgrade_block = tip

        # Transactions still in pool:
        waitFor(
            60, lambda: set(node.getrawmempool()) ==
            {t.hash
             for t in submittxes_1})

        logging.info(
            "Try sending 10000-sigcheck blocks after activation (limit: {})".
            format(MAXBLOCKSIZE // BLOCK_MAXBYTES_MAXSIGCHECKS_RATIO))
        # Send block with same txes we just tried before activation
        badblock = self.build_block(tip, submittxes_1)
        check_for_ban_on_rejected_block(
            self.pynode,
            node,
            badblock,
            reject_reason="Invalid block due to bad-blk-sigchecks",
            expect_ban=True)

        logging.info(
            "There are too many sigchecks in mempool to mine in a single block. Make sure the node won't mine invalid blocks.  Num tx: %s"
            % str(node.getmempoolinfo()))
        blk = node.generate(1)
        tip = self.getbestblock(node)
        # only 39 txes got mined.
        assert_equal(len(node.getrawmempool()), 11)

        logging.info(
            "Try sending 10000-sigcheck block with fresh transactions after activation (limit: {})"
            .format(MAXBLOCKSIZE // BLOCK_MAXBYTES_MAXSIGCHECKS_RATIO))
        # Note: in the following tests we'll be bumping timestamp in order
        # to bypass any kind of 'bad block' cache on the node, and get a
        # fresh evaluation each time.

        # Try another block with 10000 sigchecks but all fresh transactions
        badblock = self.build_block(tip,
                                    submittxes_2,
                                    nTime=SIGCHECKS_ACTIVATION_TIME + 5)
        check_for_ban_on_rejected_block(
            self.pynode,
            node,
            badblock,
            reject_reason=BLOCK_SIGCHECKS_BAD_BLOCK_SIGCHECKS)

        # Send the same txes again with different block hash. Currently we don't
        # cache valid transactions in invalid blocks so nothing changes.
        badblock = self.build_block(tip,
                                    submittxes_2,
                                    nTime=SIGCHECKS_ACTIVATION_TIME + 6)
        check_for_ban_on_rejected_block(
            self.pynode,
            node,
            badblock,
            reject_reason=BLOCK_SIGCHECKS_BAD_BLOCK_SIGCHECKS)

        # Put all the txes in mempool, in order to get them cached:
        self.pynode.send_txs_and_test(submittxes_2, node, timeout=TIMEOUT)
        # Send them again, the node still doesn't like it. But the log
        # error message has now changed because the txes failed from cache.
        badblock = self.build_block(tip,
                                    submittxes_2,
                                    nTime=SIGCHECKS_ACTIVATION_TIME + 7)
        check_for_ban_on_rejected_block(
            self.pynode,
            node,
            badblock,
            reject_reason=BLOCK_SIGCHECKS_BAD_BLOCK_SIGCHECKS)

        logging.info(
            "Try sending 8000-sigcheck block after activation (limit: {})".
            format(MAXBLOCKSIZE // BLOCK_MAXBYTES_MAXSIGCHECKS_RATIO))
        badblock = self.build_block(tip,
                                    submittxes_2[:40],
                                    nTime=SIGCHECKS_ACTIVATION_TIME + 5)
        check_for_ban_on_rejected_block(
            self.pynode,
            node,
            badblock,
            reject_reason=BLOCK_SIGCHECKS_BAD_BLOCK_SIGCHECKS)
        # redundant, but just to mirror the following test...
        node.set("consensus.maxBlockSigChecks=%d" % MAX_BLOCK_SIGCHECKS)

        logging.info(
            "Bump the excessiveblocksize limit by 1 byte, and send another block with same txes (new sigchecks limit: {})"
            .format((MAXBLOCKSIZE + 1) // BLOCK_MAXBYTES_MAXSIGCHECKS_RATIO))
        node.set("consensus.maxBlockSigChecks=%d" % (MAX_BLOCK_SIGCHECKS + 1))
        tip = self.build_block(tip,
                               submittxes_2[:40],
                               nTime=SIGCHECKS_ACTIVATION_TIME + 6)
        # It should succeed now since limit should be 8000.
        self.pynode.send_blocks_and_test([tip], node, timeout=TIMEOUT)