예제 #1
0
 def sign_tx(self, tx, spend_tx, spend_n, redeem_script, in_n, keys):
     """Sign a P2SH transaction by privkeys."""
     sighash, _ = SignatureHash(redeem_script, tx, in_n, SIGHASH_ALL)
     sigs = [
         key.sign(sighash) + bytes(bytearray([SIGHASH_ALL])) for key in keys
     ]
     tx.vin[0].scriptSig = CScript([OP_0] + sigs + [redeem_script])
     tx.rehash()
예제 #2
0
 def next_block(self,
                number,
                spend=None,
                additional_coinbase_value=0,
                script=None):
     if self.tip == None:
         base_block_hash = self.genesis_hash
     else:
         base_block_hash = self.tip.sha256
     # 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 kria to fees
     coinbase.rehash()
     block = create_block(base_block_hash, coinbase, self.block_time)
     if (spend != None):
         tx = CTransaction()
         tx.lock_height = spend.tx.lock_height
         tx.vin.append(
             CTxIn(COutPoint(spend.tx.sha256, spend.n), b"",
                   0xffffffff))  # no signature yet
         # This copies the java comparison tool testing behavior: the first
         # txout has a garbage scriptPubKey, "to make sure we're not
         # pre-verifying too much" (?)
         tx.vout.append(
             CTxOut(0, CScript([random.randint(0, 255), height & 255])))
         if script == None:
             tx.vout.append(CTxOut(1, CScript([OP_TRUE])))
         else:
             tx.vout.append(CTxOut(1, script))
         # 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,
              err) = SignatureHash(spend.tx.vout[spend.n].scriptPubKey, tx,
                                   0, SIGHASH_ALL)
             scriptSig = CScript([
                 self.coinbase_key.sign(sighash) +
                 bytes(bytearray([SIGHASH_ALL]))
             ])
         tx.vin[0].scriptSig = scriptSig
         # Now add the transaction to the block
         block = self.add_transactions_to_block(block, [tx])
     block.solve()
     self.tip = block
     self.block_heights[block.sha256] = height
     self.block_time += 1
     assert number not in self.blocks
     self.blocks[number] = block
     return block
예제 #3
0
    def next_block(self, number, spend=None, additional_coinbase_value=0, script=None, block_size=0):
        if self.tip == None:
            base_block_hash = self.genesis_hash
        else:
            base_block_hash = self.tip.sha256
        # 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.rehash()
        block = create_block(base_block_hash, coinbase, self.block_time)
        spendable_output = None
        if (spend != None):
            tx = CTransaction()
            tx.vin.append(CTxIn(COutPoint(spend.tx.sha256, spend.n), b"", 0xffffffff))  # no signature yet
            # This copies the java comparison tool testing behavior: the first
            # txout has a garbage scriptPubKey, "to make sure we're not
            # pre-verifying too much" (?)
            tx.vout.append(CTxOut(0, CScript([random.randint(0,255), height & 255])))
            if script == None:
                tx.vout.append(CTxOut(1, CScript([OP_TRUE])))
            else:
                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, err) = SignatureHash(spend.tx.vout[spend.n].scriptPubKey, tx, 0, SIGHASH_ALL)
                scriptSig = CScript([self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))])
            tx.vin[0].scriptSig = scriptSig
            # Now add the transaction to the block
            block = self.add_transactions_to_block(block, [tx])
        if spendable_output != None and block_size > 0:
            while len(block.serialize()) < block_size:
                tx = CTransaction()
                script_length = block_size - len(block.serialize()) - 79
                if script_length > 510000:
                    script_length = 500000
                script_output = CScript([b'\x00' * script_length])
                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)
                block = self.add_transactions_to_block(block, [tx])
            # 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)
            assert_equal(len(block.serialize()), block_size)
        block.solve()
        self.tip = block
        self.block_heights[block.sha256] = height
        self.block_time += 1
        assert number not in self.blocks
        self.blocks[number] = block
        return block
예제 #4
0
    def run_test(self):
        self.nodes[0].add_p2p_connection(P2PDataStore())
        self.nodeaddress = self.nodes[0].getnewaddress()
        self.pubkey = self.nodes[0].getaddressinfo(self.nodeaddress)["pubkey"]
        self.log.info("Mining %d blocks", CHAIN_HEIGHT)
        self.coinbase_txids = [
            self.nodes[0].getblock(b)['tx'][0] for b in self.nodes[0].generate(
                CHAIN_HEIGHT, self.signblockprivkey_wif)
        ]

        ##  P2PKH transaction
        ########################
        self.log.info("Test using a P2PKH transaction")
        spendtx = create_transaction(self.nodes[0],
                                     self.coinbase_txids[0],
                                     self.nodeaddress,
                                     amount=10)
        spendtx.rehash()
        copy_spendTx = CTransaction(spendtx)

        #cache hashes
        hash = spendtx.hash
        hashMalFix = spendtx.hashMalFix

        #malleate
        unDERify(spendtx)
        spendtx.rehash()

        # verify that hashMalFix remains the same even when signature is malleated and hash changes
        assert_not_equal(hash, spendtx.hash)
        assert_equal(hashMalFix, spendtx.hashMalFix)

        # verify that hash is spendtx.serialize()
        hash = encode(hash256(spendtx.serialize())[::-1],
                      'hex_codec').decode('ascii')
        assert_equal(hash, spendtx.hash)

        # verify that hashMalFix is spendtx.serialize(with_scriptsig=False)
        hashMalFix = encode(
            hash256(spendtx.serialize(with_scriptsig=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hashMalFix, spendtx.hashMalFix)

        assert_not_equal(hash, hashMalFix)
        #as this transaction does not have witness data the following is true
        assert_equal(spendtx.serialize(),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_not_equal(
            spendtx.serialize(with_witness=False),
            spendtx.serialize(with_witness=True, with_scriptsig=False))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=True),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=False),
                     spendtx.serialize_without_witness(with_scriptsig=False))

        #Create block with only non-DER signature P2PKH transaction
        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 1),
                             block_time)
        block.vtx.append(spendtx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkey)

        # serialize with and without witness block remains the same
        assert_equal(block.serialize(with_witness=True), block.serialize())
        assert_equal(block.serialize(with_witness=True),
                     block.serialize(with_witness=False))
        assert_equal(block.serialize(with_witness=True),
                     block.serialize(with_witness=False, with_scriptsig=True))

        self.log.info("Reject block with non-DER signature")
        self.nodes[0].p2p.send_and_ping(msg_block(block))
        assert_equal(self.nodes[0].getbestblockhash(), tip)

        wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(),
                   lock=mininode_lock)
        with mininode_lock:
            assert_equal(self.nodes[0].p2p.last_message["reject"].code,
                         REJECT_INVALID)
            assert_equal(self.nodes[0].p2p.last_message["reject"].data,
                         block.sha256)
            assert_equal(self.nodes[0].p2p.last_message["reject"].reason,
                         b'block-validation-failed')

        self.log.info("Accept block with DER signature")
        #recreate block with DER sig transaction
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 1),
                             block_time)
        block.vtx.append(copy_spendTx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkey)

        self.nodes[0].p2p.send_and_ping(msg_block(block))
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)

        ##  P2SH transaction
        ########################
        self.log.info("Test using P2SH transaction ")

        REDEEM_SCRIPT_1 = CScript([OP_1, OP_DROP])
        P2SH_1 = CScript([OP_HASH160, hash160(REDEEM_SCRIPT_1), OP_EQUAL])

        tx = CTransaction()
        tx.vin.append(
            CTxIn(COutPoint(int(self.coinbase_txids[1], 16), 0), b"",
                  0xffffffff))
        tx.vout.append(CTxOut(10, P2SH_1))
        tx.rehash()

        spendtx_raw = self.nodes[0].signrawtransactionwithwallet(
            ToHex(tx), [], "ALL", self.options.scheme)["hex"]
        spendtx = FromHex(spendtx, spendtx_raw)
        spendtx.rehash()
        copy_spendTx = CTransaction(spendtx)

        #cache hashes
        hash = spendtx.hash
        hashMalFix = spendtx.hashMalFix

        #malleate
        spendtxcopy = spendtx
        unDERify(spendtxcopy)
        spendtxcopy.rehash()

        # verify that hashMalFix remains the same even when signature is malleated and hash changes
        assert_not_equal(hash, spendtxcopy.hash)
        assert_equal(hashMalFix, spendtxcopy.hashMalFix)

        # verify that hash is spendtx.serialize()
        hash = encode(
            hash256(spendtx.serialize(with_witness=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hash, spendtx.hash)

        # verify that hashMalFix is spendtx.serialize(with_scriptsig=False)
        hashMalFix = encode(
            hash256(spendtx.serialize(with_witness=False,
                                      with_scriptsig=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hashMalFix, spendtx.hashMalFix)

        assert_not_equal(hash, hashMalFix)
        #as this transaction does not have witness data the following is true
        assert_equal(spendtx.serialize(),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_not_equal(
            spendtx.serialize(with_witness=False),
            spendtx.serialize(with_witness=True, with_scriptsig=False))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=True),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=False),
                     spendtx.serialize_without_witness(with_scriptsig=False))

        #Create block with only non-DER signature P2SH transaction
        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 2),
                             block_time)
        block.vtx.append(spendtx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkey)

        # serialize with and without witness block remains the same
        assert_equal(block.serialize(with_witness=True), block.serialize())
        assert_equal(block.serialize(with_witness=True),
                     block.serialize(with_witness=False))
        assert_equal(block.serialize(with_witness=True),
                     block.serialize(with_witness=True, with_scriptsig=True))

        self.log.info("Reject block with non-DER signature")
        self.nodes[0].p2p.send_and_ping(msg_block(block))
        assert_equal(self.nodes[0].getbestblockhash(), tip)

        wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(),
                   lock=mininode_lock)
        with mininode_lock:
            assert_equal(self.nodes[0].p2p.last_message["reject"].code,
                         REJECT_INVALID)
            assert_equal(self.nodes[0].p2p.last_message["reject"].data,
                         block.sha256)
            assert_equal(self.nodes[0].p2p.last_message["reject"].reason,
                         b'block-validation-failed')

        self.log.info("Accept block with DER signature")
        #recreate block with DER sig transaction
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 2),
                             block_time)
        block.vtx.append(copy_spendTx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkey)

        self.nodes[0].p2p.send_and_ping(msg_block(block))
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)

        ## redeem previous P2SH
        #########################
        self.log.info("Test using P2SH redeem transaction ")

        tx = CTransaction()
        tx.vout.append(CTxOut(1, CScript([OP_TRUE])))
        tx.vin.append(CTxIn(COutPoint(block.vtx[1].malfixsha256, 0), b''))

        (sighash, err) = SignatureHash(REDEEM_SCRIPT_1, tx, 1, SIGHASH_ALL)
        signKey = CECKey()
        signKey.set_secretbytes(b"horsebattery")
        sig = signKey.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))
        scriptSig = CScript([sig, REDEEM_SCRIPT_1])

        tx.vin[0].scriptSig = scriptSig
        tx.rehash()

        spendtx_raw = self.nodes[0].signrawtransactionwithwallet(
            ToHex(tx), [], "ALL", self.options.scheme)["hex"]
        spendtx = FromHex(spendtx, spendtx_raw)
        spendtx.rehash()

        #cache hashes
        hash = spendtx.hash
        hashMalFix = spendtx.hashMalFix

        #malleate
        spendtxcopy = spendtx
        unDERify(spendtxcopy)
        spendtxcopy.rehash()

        # verify that hashMalFix remains the same even when signature is malleated and hash changes
        assert_not_equal(hash, spendtxcopy.hash)
        assert_equal(hashMalFix, spendtxcopy.hashMalFix)

        # verify that hash is spendtx.serialize()
        hash = encode(
            hash256(spendtx.serialize(with_witness=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hash, spendtx.hash)

        # verify that hashMalFix is spendtx.serialize(with_scriptsig=False)
        hashMalFix = encode(
            hash256(spendtx.serialize(with_witness=False,
                                      with_scriptsig=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hashMalFix, spendtx.hashMalFix)

        assert_not_equal(hash, hashMalFix)
        #as this transaction does not have witness data the following is true
        assert_equal(spendtx.serialize(),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_not_equal(
            spendtx.serialize(with_witness=False),
            spendtx.serialize(with_witness=True, with_scriptsig=False))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=True),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=False),
                     spendtx.serialize_without_witness(with_scriptsig=False))

        #Create block with only non-DER signature P2SH redeem transaction
        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 3),
                             block_time)
        block.vtx.append(spendtx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkey)

        # serialize with and without witness block remains the same
        assert_equal(block.serialize(with_witness=True), block.serialize())
        assert_equal(block.serialize(with_witness=True),
                     block.serialize(with_witness=False))
        assert_equal(block.serialize(with_witness=True),
                     block.serialize(with_witness=True, with_scriptsig=True))

        self.log.info("Accept block with P2SH redeem transaction")
        self.nodes[0].p2p.send_and_ping(msg_block(block))
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)

        ##  p2sh_p2wpkh transaction
        ##############################
        self.log.info("Test using p2sh_p2wpkh transaction ")
        spendtxStr = create_witness_tx(self.nodes[0],
                                       True,
                                       getInput(self.coinbase_txids[4]),
                                       self.pubkey,
                                       amount=1.0)

        #get CTRansaction object from above hex
        spendtx = CTransaction()
        spendtx.deserialize(BytesIO(hex_str_to_bytes(spendtxStr)))
        spendtx.rehash()

        #cache hashes
        spendtx.rehash()
        hash = spendtx.hash
        hashMalFix = spendtx.hashMalFix
        withash = spendtx.calc_sha256(True)

        # malleate
        unDERify(spendtx)
        spendtx.rehash()
        withash2 = spendtx.calc_sha256(True)

        # verify that hashMalFix remains the same even when signature is malleated and hash changes
        assert_equal(withash, withash2)
        assert_equal(hash, spendtx.hash)
        assert_equal(hashMalFix, spendtx.hashMalFix)

        # verify that hash is spendtx.serialize()
        hash = encode(hash256(spendtx.serialize())[::-1],
                      'hex_codec').decode('ascii')
        assert_equal(hash, spendtx.hash)

        # verify that hashMalFix is spendtx.serialize(with_scriptsig=False)
        hashMalFix = encode(
            hash256(spendtx.serialize(with_scriptsig=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hashMalFix, spendtx.hashMalFix)

        assert_not_equal(hash, hashMalFix)
        #as this transaction does not have witness data the following is true
        assert_equal(spendtx.serialize(),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_not_equal(
            spendtx.serialize(with_witness=False),
            spendtx.serialize(with_witness=True, with_scriptsig=False))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=True),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=False),
                     spendtx.serialize_without_witness(with_scriptsig=False))

        #Create block with only non-DER signature p2sh_p2wpkh transaction
        spendtxStr = self.nodes[0].signrawtransactionwithwallet(
            spendtxStr, [], "ALL", self.options.scheme)
        assert ("errors" not in spendtxStr or len(["errors"]) == 0)
        spendtxStr = spendtxStr["hex"]
        spendtx = CTransaction()
        spendtx.deserialize(BytesIO(hex_str_to_bytes(spendtxStr)))
        spendtx.rehash()

        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 4),
                             block_time)
        block.vtx.append(spendtx)
        add_witness_commitment(block)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkey)

        # serialize with and without witness
        assert_equal(block.serialize(with_witness=False), block.serialize())
        assert_not_equal(block.serialize(with_witness=True),
                         block.serialize(with_witness=False))
        assert_not_equal(
            block.serialize(with_witness=True),
            block.serialize(with_witness=False, with_scriptsig=True))

        self.log.info(
            "Reject block with p2sh_p2wpkh transaction and witness commitment")
        assert_raises_rpc_error(
            -22, "Block does not start with a coinbase",
            self.nodes[0].submitblock,
            bytes_to_hex_str(block.serialize(with_witness=True)))
        assert_equal(self.nodes[0].getbestblockhash(), tip)

        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 4),
                             block_time)
        block.vtx.append(spendtx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkey)

        self.log.info("Accept block with p2sh_p2wpkh transaction")
        self.nodes[0].submitblock(
            bytes_to_hex_str(block.serialize(with_witness=True)))
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)

        ##  p2sh_p2wsh transaction
        ##############################
        self.log.info("Test using p2sh_p2wsh transaction")
        spendtxStr = create_witness_tx(self.nodes[0],
                                       True,
                                       getInput(self.coinbase_txids[5]),
                                       self.pubkey,
                                       amount=1.0)

        #get CTRansaction object from above hex
        spendtx = CTransaction()
        spendtx.deserialize(BytesIO(hex_str_to_bytes(spendtxStr)))
        spendtx.rehash()

        #cache hashes
        spendtx.rehash()
        hash = spendtx.hash
        hashMalFix = spendtx.hashMalFix
        withash = spendtx.calc_sha256(True)

        # malleate
        unDERify(spendtx)
        spendtx.rehash()
        withash2 = spendtx.calc_sha256(True)

        # verify that hashMalFix remains the same even when signature is malleated and hash changes
        assert_equal(withash, withash2)
        assert_equal(hash, spendtx.hash)
        assert_equal(hashMalFix, spendtx.hashMalFix)

        # verify that hash is spendtx.serialize()
        hash = encode(hash256(spendtx.serialize())[::-1],
                      'hex_codec').decode('ascii')
        assert_equal(hash, spendtx.hash)

        # verify that hashMalFix is spendtx.serialize(with_scriptsig=False)
        hashMalFix = encode(
            hash256(spendtx.serialize(with_scriptsig=False))[::-1],
            'hex_codec').decode('ascii')
        assert_equal(hashMalFix, spendtx.hashMalFix)

        assert_not_equal(hash, hashMalFix)
        #as this transaction does not have witness data the following is true
        assert_equal(spendtx.serialize(),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize(with_witness=True, with_scriptsig=True))
        assert_not_equal(
            spendtx.serialize(with_witness=False),
            spendtx.serialize(with_witness=True, with_scriptsig=False))
        assert_equal(spendtx.serialize(with_witness=False),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=True),
                     spendtx.serialize_without_witness(with_scriptsig=True))
        assert_equal(spendtx.serialize_with_witness(with_scriptsig=False),
                     spendtx.serialize_without_witness(with_scriptsig=False))

        #Create block with only non-DER signature p2sh_p2wsh transaction
        spendtxStr = self.nodes[0].signrawtransactionwithwallet(
            spendtxStr, [], "ALL", self.options.scheme)
        assert ("errors" not in spendtxStr or len(["errors"]) == 0)
        spendtxStr = spendtxStr["hex"]
        spendtx = CTransaction()
        spendtx.deserialize(BytesIO(hex_str_to_bytes(spendtxStr)))
        spendtx.rehash()

        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 5),
                             block_time)
        block.vtx.append(spendtx)
        add_witness_commitment(block)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkey)

        # serialize with and without witness
        assert_equal(block.serialize(with_witness=False), block.serialize())
        assert_not_equal(block.serialize(with_witness=True),
                         block.serialize(with_witness=False))
        assert_not_equal(
            block.serialize(with_witness=True),
            block.serialize(with_witness=False, with_scriptsig=True))

        self.log.info(
            "Reject block with p2sh_p2wsh transaction and witness commitment")
        assert_raises_rpc_error(
            -22, "Block does not start with a coinbase",
            self.nodes[0].submitblock,
            bytes_to_hex_str(block.serialize(with_witness=True)))
        assert_equal(self.nodes[0].getbestblockhash(), tip)

        block = create_block(int(tip, 16), create_coinbase(CHAIN_HEIGHT + 5),
                             block_time)
        block.vtx.append(spendtx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.hashImMerkleRoot = block.calc_immutable_merkle_root()
        block.rehash()
        block.solve(self.signblockprivkey)

        self.log.info("Accept block with p2sh_p2wsh transaction")
        self.nodes[0].submitblock(
            bytes_to_hex_str(block.serialize(with_witness=True)))
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)
    def run_test(self):
        node = self.nodes[0]  # convenience reference to the node
        self.address = node.getnewaddress()
        node.add_p2p_connection(P2PDataStore())
        node.p2p.wait_for_getheaders(timeout=5)
        self.address = self.nodes[0].getnewaddress()

        self.log.info("Test starting...")

        #generate 10 blocks for coinbase outputs
        coinbase_txs = []
        for i in range(1, 10):
            height = node.getblockcount() + 1
            coinbase_tx = create_coinbase(height, self.coinbase_pubkey)
            coinbase_txs.append(coinbase_tx)
            tip = node.getbestblockhash()
            block_time = node.getblockheader(tip)["mediantime"] + 1
            block = create_block(int(tip, 16), coinbase_tx, block_time)
            block.solve(self.signblockprivkey)
            tip = block.hash

            node.p2p.send_and_ping(msg_block(block))
            assert_equal(node.getbestblockhash(), tip)

        change_script = CScript([self.coinbase_pubkey, OP_CHECKSIG])
        burn_script = CScript([hex_str_to_bytes(self.pubkeys[1]), OP_CHECKSIG])

        #TxSuccess1 - coinbaseTx1 - issue 100 REISSUABLE  + 30     (UTXO-1,2)
        colorId_reissuable = colorIdReissuable(
            coinbase_txs[0].vout[0].scriptPubKey)
        script_reissuable = CP2PHK_script(colorId=colorId_reissuable,
                                          pubkey=self.pubkeys[0])
        script_transfer_reissuable = CP2PHK_script(colorId=colorId_reissuable,
                                                   pubkey=self.pubkeys[1])

        txSuccess1 = CTransaction()
        txSuccess1.vin.append(
            CTxIn(COutPoint(coinbase_txs[0].malfixsha256, 0), b""))
        txSuccess1.vout.append(CTxOut(100, script_reissuable))
        txSuccess1.vout.append(
            CTxOut(30 * COIN, CScript([self.coinbase_pubkey, OP_CHECKSIG])))
        sig_hash, err = SignatureHash(coinbase_txs[0].vout[0].scriptPubKey,
                                      txSuccess1, 0, SIGHASH_ALL)
        signature = self.coinbase_key.sign(
            sig_hash) + b'\x01'  # 0x1 is SIGHASH_ALL
        txSuccess1.vin[0].scriptSig = CScript([signature])
        txSuccess1.rehash()

        test_transaction_acceptance(node, txSuccess1, accepted=True)

        #TxSuccess2 - (UTXO-2)    - issue 100 NON-REISSUABLE       (UTXO-3)
        colorId_nonreissuable = colorIdNonReissuable(
            COutPoint(txSuccess1.malfixsha256, 1).serialize())
        script_nonreissuable = CP2PHK_script(colorId=colorId_nonreissuable,
                                             pubkey=self.pubkeys[0])
        script_transfer_nonreissuable = CP2PHK_script(
            colorId=colorId_nonreissuable, pubkey=self.pubkeys[1])

        txSuccess2 = CTransaction()
        txSuccess2.vin.append(CTxIn(COutPoint(txSuccess1.malfixsha256, 1),
                                    b""))
        txSuccess2.vout.append(CTxOut(100, script_nonreissuable))
        sig_hash, err = SignatureHash(txSuccess1.vout[1].scriptPubKey,
                                      txSuccess2, 0, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess2.vin[0].scriptSig = CScript([signature])
        txSuccess2.rehash()

        test_transaction_acceptance(node, txSuccess2, accepted=True)

        #TxSuccess3 - coinbaseTx2 - issue 1 NFT                    (UTXO-4)
        colorId_nft = colorIdNFT(
            COutPoint(coinbase_txs[1].malfixsha256, 0).serialize())
        script_nft = CP2PHK_script(colorId=colorId_nft, pubkey=self.pubkeys[0])
        script_transfer_nft = CP2PHK_script(colorId=colorId_nft,
                                            pubkey=self.pubkeys[0])

        txSuccess3 = CTransaction()
        txSuccess3.vin.append(
            CTxIn(COutPoint(coinbase_txs[1].malfixsha256, 0), b""))
        txSuccess3.vout.append(CTxOut(1, script_nft))
        sig_hash, err = SignatureHash(coinbase_txs[1].vout[0].scriptPubKey,
                                      txSuccess3, 0, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess3.vin[0].scriptSig = CScript([signature])
        txSuccess3.rehash()

        test_transaction_acceptance(node, txSuccess3, accepted=True)

        #TxFailure4 - (UTXO-1)    - split REISSUABLE - 25 + 75     (UTXO-5,6)
        #           - (UTXO-3)    - split NON-REISSUABLE - 40 + 60 (UTXO-7,8)
        #           - coinbaseTx3 - issue 100 REISSUABLE           (UTXO-9)
        TxFailure4 = CTransaction()
        TxFailure4.vin.append(CTxIn(COutPoint(txSuccess1.malfixsha256, 0),
                                    b""))
        TxFailure4.vin.append(CTxIn(COutPoint(txSuccess2.malfixsha256, 0),
                                    b""))
        TxFailure4.vin.append(
            CTxIn(COutPoint(coinbase_txs[2].malfixsha256, 0), b""))
        TxFailure4.vout.append(CTxOut(25, script_reissuable))
        TxFailure4.vout.append(CTxOut(75, script_reissuable))
        TxFailure4.vout.append(CTxOut(40, script_nonreissuable))
        TxFailure4.vout.append(CTxOut(60, script_nonreissuable))
        TxFailure4.vout.append(CTxOut(100, script_reissuable))
        sig_hash, err = SignatureHash(txSuccess1.vout[0].scriptPubKey,
                                      TxFailure4, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure4.vin[0].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess2.vout[0].scriptPubKey,
                                      TxFailure4, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure4.vin[1].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[2].vout[0].scriptPubKey,
                                      TxFailure4, 2, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        TxFailure4.vin[2].scriptSig = CScript([signature])
        TxFailure4.rehash()

        test_transaction_acceptance(node,
                                    TxFailure4,
                                    accepted=False,
                                    reason=b"bad-txns-token-balance")

        #TxSuccess4 - (UTXO-1)    - split REISSUABLE - 25 + 75     (UTXO-5,6)
        #           - (UTXO-3)    - split NON-REISSUABLE - 40 + 60 (UTXO-7,8)
        txSuccess4 = CTransaction()
        txSuccess4.vin.append(CTxIn(COutPoint(txSuccess1.malfixsha256, 0),
                                    b""))
        txSuccess4.vin.append(CTxIn(COutPoint(txSuccess2.malfixsha256, 0),
                                    b""))
        txSuccess4.vin.append(
            CTxIn(COutPoint(coinbase_txs[2].malfixsha256, 0), b""))
        txSuccess4.vout.append(CTxOut(25, script_reissuable))
        txSuccess4.vout.append(CTxOut(75, script_reissuable))
        txSuccess4.vout.append(CTxOut(40, script_nonreissuable))
        txSuccess4.vout.append(CTxOut(60, script_nonreissuable))
        sig_hash, err = SignatureHash(txSuccess1.vout[0].scriptPubKey,
                                      txSuccess4, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess4.vin[0].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess2.vout[0].scriptPubKey,
                                      txSuccess4, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess4.vin[1].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[2].vout[0].scriptPubKey,
                                      txSuccess4, 2, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess4.vin[2].scriptSig = CScript([signature])
        txSuccess4.rehash()

        test_transaction_acceptance(node, txSuccess4, accepted=True)

        #TxFailure5 - (UTXO-6)    - split REISSUABLE(75)           (UTXO-10,11)
        #           - (UTXO-7)    - split NON-REISSUABLE(40)       (UTXO-12)
        #           - (UTXO-4)    - split NFT                      (UTXO-13)
        #           - coinbaseTx4
        TxFailure5 = CTransaction()
        TxFailure5.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 1),
                                    b""))
        TxFailure5.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 2),
                                    b""))
        TxFailure5.vin.append(CTxIn(COutPoint(txSuccess3.malfixsha256, 0),
                                    b""))
        TxFailure5.vin.append(
            CTxIn(COutPoint(coinbase_txs[3].malfixsha256, 0), b""))
        TxFailure5.vout.append(CTxOut(35, script_reissuable))
        TxFailure5.vout.append(CTxOut(40, script_reissuable))
        TxFailure5.vout.append(CTxOut(20, script_nonreissuable))
        TxFailure5.vout.append(CTxOut(20, script_nonreissuable))
        TxFailure5.vout.append(CTxOut(1, script_nft))
        TxFailure5.vout.append(CTxOut(1, script_nft))
        sig_hash, err = SignatureHash(txSuccess4.vout[1].scriptPubKey,
                                      TxFailure5, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure5.vin[0].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess4.vout[2].scriptPubKey,
                                      TxFailure5, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure5.vin[1].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess3.vout[0].scriptPubKey,
                                      TxFailure5, 2, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure5.vin[2].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[3].vout[0].scriptPubKey,
                                      TxFailure5, 3, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        TxFailure5.vin[3].scriptSig = CScript([signature])
        TxFailure5.rehash()

        test_transaction_acceptance(node,
                                    TxFailure5,
                                    accepted=False,
                                    reason=b"bad-txns-token-balance")

        #txSuccess5 - (UTXO-6)    - split REISSUABLE(75)           (UTXO-10,11)
        #           - (UTXO-7)    - split NON-REISSUABLE(40)       (UTXO-12)
        #           - (UTXO-4)    - transfer NFT                      (UTXO-13)
        #           - coinbaseTx4
        txSuccess5 = CTransaction()
        txSuccess5.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 1),
                                    b""))
        txSuccess5.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 2),
                                    b""))
        txSuccess5.vin.append(CTxIn(COutPoint(txSuccess3.malfixsha256, 0),
                                    b""))
        txSuccess5.vin.append(
            CTxIn(COutPoint(coinbase_txs[3].malfixsha256, 0), b""))
        txSuccess5.vout.append(CTxOut(35, script_reissuable))
        txSuccess5.vout.append(CTxOut(40, script_reissuable))
        txSuccess5.vout.append(CTxOut(20, script_nonreissuable))
        txSuccess5.vout.append(CTxOut(20, script_nonreissuable))
        txSuccess5.vout.append(CTxOut(1, script_nft))
        sig_hash, err = SignatureHash(txSuccess4.vout[1].scriptPubKey,
                                      txSuccess5, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess5.vin[0].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess4.vout[2].scriptPubKey,
                                      txSuccess5, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess5.vin[1].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess3.vout[0].scriptPubKey,
                                      txSuccess5, 2, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess5.vin[2].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[3].vout[0].scriptPubKey,
                                      txSuccess5, 3, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess5.vin[3].scriptSig = CScript([signature])
        txSuccess5.rehash()

        test_transaction_acceptance(node, txSuccess5, accepted=True)

        #TxFailure6 - (UTXO-11)   - transfer REISSUABLE(40)        (UTXO-14)
        #           - (UTXO-8)    - burn NON-REISSUABLE(60)        (UTXO-15)*
        #           - (UTXO-13)   - transfer NFT                   (UTXO-16)
        #           - coinbaseTx5 - issue 1000 REISSUABLE1, change (UTXO-17)
        colorId_reissuable1 = colorIdReissuable(
            coinbase_txs[6].vout[0].scriptPubKey)
        script_reissuable1 = CP2PHK_script(colorId=colorId_reissuable,
                                           pubkey=self.pubkeys[0])

        TxFailure6 = CTransaction()
        TxFailure6.vin.append(CTxIn(COutPoint(txSuccess5.malfixsha256, 1),
                                    b""))
        TxFailure6.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 3),
                                    b""))
        TxFailure6.vin.append(CTxIn(COutPoint(txSuccess5.malfixsha256, 4),
                                    b""))
        TxFailure6.vin.append(
            CTxIn(COutPoint(coinbase_txs[4].malfixsha256, 0), b""))
        TxFailure6.vout.append(CTxOut(40, script_transfer_reissuable))
        TxFailure6.vout.append(CTxOut(30, script_transfer_nonreissuable))
        TxFailure6.vout.append(CTxOut(1, script_transfer_nft))
        TxFailure6.vout.append(CTxOut(1000, script_reissuable1))
        TxFailure6.vout.append(CTxOut(1 * COIN, change_script))
        sig_hash, err = SignatureHash(txSuccess5.vout[1].scriptPubKey,
                                      TxFailure6, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure6.vin[0].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess4.vout[3].scriptPubKey,
                                      TxFailure6, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure6.vin[1].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess5.vout[4].scriptPubKey,
                                      TxFailure6, 2, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure6.vin[2].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[4].vout[0].scriptPubKey,
                                      TxFailure6, 3, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        TxFailure6.vin[3].scriptSig = CScript([signature])
        TxFailure6.rehash()

        test_transaction_acceptance(node,
                                    TxFailure6,
                                    accepted=False,
                                    reason=b"bad-txns-token-balance")

        #TxSuccess6 - (UTXO-11)   - transfer REISSUABLE(40)        (UTXO-14)
        #           - (UTXO-8)    - burn NON-REISSUABLE(60)        (UTXO-15)*
        #           - (UTXO-13)   - transfer NFT                   (UTXO-16)
        #           - coinbaseTx5 - change
        txSuccess6 = CTransaction()
        txSuccess6.vin.append(CTxIn(COutPoint(txSuccess5.malfixsha256, 1),
                                    b""))
        txSuccess6.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 3),
                                    b""))
        txSuccess6.vin.append(CTxIn(COutPoint(txSuccess5.malfixsha256, 4),
                                    b""))
        txSuccess6.vin.append(
            CTxIn(COutPoint(coinbase_txs[4].malfixsha256, 0), b""))
        txSuccess6.vout.append(CTxOut(40, script_transfer_reissuable))
        txSuccess6.vout.append(CTxOut(30, script_transfer_nonreissuable))
        txSuccess6.vout.append(CTxOut(1, script_transfer_nft))
        txSuccess6.vout.append(CTxOut(1 * COIN, change_script))
        sig_hash, err = SignatureHash(txSuccess5.vout[1].scriptPubKey,
                                      txSuccess6, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess6.vin[0].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess4.vout[3].scriptPubKey,
                                      txSuccess6, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess6.vin[1].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess5.vout[4].scriptPubKey,
                                      txSuccess6, 2, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess6.vin[2].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[4].vout[0].scriptPubKey,
                                      txSuccess6, 3, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess6.vin[3].scriptSig = CScript([signature])
        txSuccess6.rehash()

        test_transaction_acceptance(node, txSuccess6, accepted=True)

        #TxSuccess7 - coinbaseTx5 - issue 1000 REISSUABLE1, change (UTXO-17)
        txSuccess7 = CTransaction()
        txSuccess7.vin.append(
            CTxIn(COutPoint(coinbase_txs[5].malfixsha256, 0), b""))
        txSuccess7.vout.append(CTxOut(1000, script_reissuable1))
        sig_hash, err = SignatureHash(coinbase_txs[5].vout[0].scriptPubKey,
                                      txSuccess7, 0, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess7.vin[0].scriptSig = CScript([signature])
        txSuccess7.rehash()

        test_transaction_acceptance(node, txSuccess7, accepted=True)

        #TxFailure7 - (UTXO-9,14) - aggregate REISSUABLE(25 + 40) x
        #           - (UTXO-12)   - burn NON-REISSUABLE(20)        *
        TxFailure7 = CTransaction()
        TxFailure7.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 0),
                                    b""))
        TxFailure7.vin.append(CTxIn(COutPoint(txSuccess6.malfixsha256, 0),
                                    b""))
        TxFailure7.vin.append(CTxIn(COutPoint(txSuccess5.malfixsha256, 2),
                                    b""))
        TxFailure7.vout.append(CTxOut(65, script_transfer_reissuable))
        sig_hash, err = SignatureHash(txSuccess4.vout[0].scriptPubKey,
                                      TxFailure7, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure7.vin[0].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess6.vout[0].scriptPubKey,
                                      TxFailure7, 1, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure7.vin[1].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess5.vout[2].scriptPubKey,
                                      TxFailure7, 2, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        TxFailure7.vin[2].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        TxFailure7.rehash()

        test_transaction_acceptance(node,
                                    TxFailure7,
                                    accepted=False,
                                    reason=b'min relay fee not met')

        #txSuccess8 - (UTXO-9,14) - aggregate REISSUABLE(25 + 40) x
        #           - (UTXO-12)   - burn NON-REISSUABLE(20)        *
        #           - coinbase[6]
        txSuccess8 = CTransaction()
        txSuccess8.vin.append(CTxIn(COutPoint(txSuccess4.malfixsha256, 0),
                                    b""))
        txSuccess8.vin.append(CTxIn(COutPoint(txSuccess6.malfixsha256, 0),
                                    b""))
        txSuccess8.vin.append(CTxIn(COutPoint(txSuccess5.malfixsha256, 2),
                                    b""))
        txSuccess8.vin.append(
            CTxIn(COutPoint(coinbase_txs[6].malfixsha256, 0), b""))
        txSuccess8.vout.append(CTxOut(65, script_transfer_reissuable))
        sig_hash, err = SignatureHash(txSuccess4.vout[0].scriptPubKey,
                                      txSuccess8, 0, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess8.vin[0].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(txSuccess6.vout[0].scriptPubKey,
                                      txSuccess8, 1, SIGHASH_ALL)
        signature = self.privkeys[1].sign(sig_hash) + b'\x01'
        txSuccess8.vin[1].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[1])])
        sig_hash, err = SignatureHash(txSuccess5.vout[2].scriptPubKey,
                                      txSuccess8, 2, SIGHASH_ALL)
        signature = self.privkeys[0].sign(sig_hash) + b'\x01'
        txSuccess8.vin[2].scriptSig = CScript(
            [signature, hex_str_to_bytes(self.pubkeys[0])])
        sig_hash, err = SignatureHash(coinbase_txs[6].vout[0].scriptPubKey,
                                      txSuccess8, 3, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        txSuccess8.vin[3].scriptSig = CScript([signature])
        txSuccess8.rehash()

        test_transaction_acceptance(node, txSuccess8, accepted=True)

        #TxFailure8 - (UTXO-17)   - convert REISSUABLE to NON-REISSUABLE
        TxFailure8 = CTransaction()
        TxFailure8.vin.append(CTxIn(COutPoint(txSuccess7.malfixsha256, 0),
                                    b""))
        TxFailure8.vout.append(CTxOut(60, script_transfer_nonreissuable))
        sig_hash, err = SignatureHash(txSuccess7.vout[0].scriptPubKey,
                                      TxFailure8, 0, SIGHASH_ALL)
        signature = self.coinbase_key.sign(sig_hash) + b'\x01'
        TxFailure8.vin[0].scriptSig = CScript([signature])
        TxFailure8.rehash()

        test_transaction_acceptance(node,
                                    TxFailure8,
                                    accepted=False,
                                    reason=b'invalid-colorid')
예제 #6
0
    def run_test(self):
        node = self.nodes[0]  # convenience reference to the node

        self.bootstrap_p2p()  # Add one p2p connection to the node

        best_block = self.nodes[0].getbestblockhash()
        tip = int(best_block, 16)
        best_block_time = self.nodes[0].getblock(best_block)['time']
        block_time = best_block_time + 1

        privkey = b"aa3680d5d48a8283413f7a108367c7299ca73f553735860a87b08f39395618b7"
        key = CECKey()
        key.set_secretbytes(privkey)
        key.set_compressed(True)
        pubkey = CPubKey(key.get_pubkey())
        pubkeyhash = hash160(pubkey)
        SCRIPT_PUB_KEY = CScript([
            CScriptOp(OP_DUP),
            CScriptOp(OP_HASH160), pubkeyhash,
            CScriptOp(OP_EQUALVERIFY),
            CScriptOp(OP_CHECKSIG)
        ])

        self.log.info("Create a new block with an anyone-can-spend coinbase.")
        height = 1
        block = create_block(tip, create_coinbase(height, pubkey), block_time)
        block.solve(self.signblockprivkey)
        # Save the coinbase for later
        block1 = block
        tip = block.sha256
        node.p2p.send_blocks_and_test([block], node, success=True)

        # b'\x64' is OP_NOTIF
        # Transaction will be rejected with code 16 (REJECT_INVALID)
        self.log.info('Test a transaction that is rejected')
        tx1 = create_tx_with_script(block1.vtx[0],
                                    0,
                                    script_sig=b'\x64' * 35,
                                    amount=50 * COIN - 12000)
        node.p2p.send_txs_and_test([tx1],
                                   node,
                                   success=False,
                                   expect_disconnect=False)

        # Make two p2p connections to provide the node with orphans
        # * p2ps[0] will send valid orphan txs (one with low fee)
        # * p2ps[1] will send an invalid orphan tx (and is later disconnected for that)
        self.reconnect_p2p(num_connections=2)

        self.log.info('Test orphan transaction handling ... ')
        # Create a root transaction that we withhold until all dependend transactions
        # are sent out and in the orphan cache
        tx_withhold = CTransaction()
        tx_withhold.vin.append(
            CTxIn(outpoint=COutPoint(block1.vtx[0].malfixsha256, 0)))
        tx_withhold.vout.append(
            CTxOut(nValue=50 * COIN - 12000, scriptPubKey=SCRIPT_PUB_KEY))
        tx_withhold.calc_sha256()
        (sighash, err) = SignatureHash(CScript([pubkey, OP_CHECKSIG]),
                                       tx_withhold, 0, SIGHASH_ALL)
        signature = key.sign(sighash) + b'\x01'  # 0x1 is SIGHASH_ALL
        tx_withhold.vin[0].scriptSig = CScript([signature])

        # Our first orphan tx with some outputs to create further orphan txs
        tx_orphan_1 = CTransaction()
        tx_orphan_1.vin.append(
            CTxIn(outpoint=COutPoint(tx_withhold.malfixsha256, 0)))
        tx_orphan_1.vout = [
            CTxOut(nValue=10 * COIN, scriptPubKey=SCRIPT_PUB_KEY)
        ] * 3
        tx_orphan_1.calc_sha256()
        (sighash, err) = SignatureHash(SCRIPT_PUB_KEY, tx_orphan_1, 0,
                                       SIGHASH_ALL)
        signature = key.sign(sighash) + b'\x01'  # 0x1 is SIGHASH_ALL
        tx_orphan_1.vin[0].scriptSig = CScript([signature, pubkey])

        # A valid transaction with low fee
        tx_orphan_2_no_fee = CTransaction()
        tx_orphan_2_no_fee.vin.append(
            CTxIn(outpoint=COutPoint(tx_orphan_1.malfixsha256, 0)))
        tx_orphan_2_no_fee.vout.append(
            CTxOut(nValue=10 * COIN, scriptPubKey=SCRIPT_PUB_KEY))
        (sighash, err) = SignatureHash(SCRIPT_PUB_KEY, tx_orphan_2_no_fee, 0,
                                       SIGHASH_ALL)
        signature = key.sign(sighash) + b'\x01'  # 0x1 is SIGHASH_ALL
        tx_orphan_2_no_fee.vin[0].scriptSig = CScript([signature, pubkey])

        # A valid transaction with sufficient fee
        tx_orphan_2_valid = CTransaction()
        tx_orphan_2_valid.vin.append(
            CTxIn(outpoint=COutPoint(tx_orphan_1.malfixsha256, 1)))
        tx_orphan_2_valid.vout.append(
            CTxOut(nValue=10 * COIN - 12000, scriptPubKey=SCRIPT_PUB_KEY))
        tx_orphan_2_valid.calc_sha256()
        (sighash, err) = SignatureHash(SCRIPT_PUB_KEY, tx_orphan_2_valid, 0,
                                       SIGHASH_ALL)
        signature = key.sign(sighash) + b'\x01'  # 0x1 is SIGHASH_ALL
        tx_orphan_2_valid.vin[0].scriptSig = CScript([signature, pubkey])

        # An invalid transaction with negative fee
        tx_orphan_2_invalid = CTransaction()
        tx_orphan_2_invalid.vin.append(
            CTxIn(outpoint=COutPoint(tx_orphan_1.malfixsha256, 2)))
        tx_orphan_2_invalid.vout.append(
            CTxOut(nValue=11 * COIN, scriptPubKey=SCRIPT_PUB_KEY))
        (sighash, err) = SignatureHash(SCRIPT_PUB_KEY, tx_orphan_2_invalid, 0,
                                       SIGHASH_ALL)
        signature = key.sign(sighash) + b'\x01'  # 0x1 is SIGHASH_ALL
        tx_orphan_2_invalid.vin[0].scriptSig = CScript([signature, pubkey])

        self.log.info('Send the orphans ... ')
        # Send valid orphan txs from p2ps[0]
        node.p2p.send_txs_and_test(
            [tx_orphan_1, tx_orphan_2_no_fee, tx_orphan_2_valid],
            node,
            success=False)
        # Send invalid tx from p2ps[1]
        node.p2ps[1].send_txs_and_test([tx_orphan_2_invalid],
                                       node,
                                       success=False)

        assert_equal(0,
                     node.getmempoolinfo()['size'])  # Mempool should be empty
        assert_equal(2, len(node.getpeerinfo()))  # p2ps[1] is still connected

        self.log.info('Send the withhold tx ... ')
        node.p2p.send_txs_and_test([tx_withhold], node, success=True)

        # Transactions that should end up in the mempool
        expected_mempool = {
            t.hashMalFix
            for t in [
                tx_withhold,  # The transaction that is the root for all orphans
                tx_orphan_1,  # The orphan transaction that splits the coins
                tx_orphan_2_valid,  # The valid transaction (with sufficient fee)
            ]
        }
        # Transactions that do not end up in the mempool
        # tx_orphan_no_fee, because it has too low fee (p2ps[0] is not disconnected for relaying that tx)
        # tx_orphan_invaid, because it has negative fee (p2ps[1] is disconnected for relaying that tx)

        wait_until(lambda: 1 == len(node.getpeerinfo()),
                   timeout=12)  # p2ps[1] is no longer connected
        assert_equal(expected_mempool, set(node.getrawmempool()))

        # restart node with sending BIP61 messages disabled, check that it disconnects without sending the reject message
        self.log.info(
            'Test a transaction that is rejected, with BIP61 disabled')
        self.restart_node(0, ['-enablebip61=0', '-persistmempool=0'])
        self.reconnect_p2p(num_connections=1)
        node.p2p.send_txs_and_test([tx1],
                                   node,
                                   success=False,
                                   expect_disconnect=False)
        # send_txs_and_test will have waited for disconnect, so we can safely check that no reject has been received
        assert_equal(node.p2p.reject_code_received, None)
예제 #7
0
    def run_test(self):
        self.test_node = self.nodes[0].add_p2p_connection(P2PDataStore())

        self.log.info("Running signed block tests")
        assert_equal(self.nodes[0].getblockcount(), 0)
        genesisblock_hash = int(self.nodes[0].getbestblockhash(), 16)

        # create 1 spendable coinbase
        height = 1
        block_time = int(time())
        block1 = create_block(genesisblock_hash, create_coinbase(height),
                              block_time)
        block1.rehash()
        block1.solve(self.secret)
        self.nodes[0].p2p.send_blocks_and_test([block1],
                                               self.nodes[0],
                                               success=True)
        self.nodes[0].generate(100, self.secret)
        previousblock_hash = int(self.nodes[0].getbestblockhash(), 16)

        # create a test block
        height = 102
        block_time = int(time())
        block = create_block(previousblock_hash, create_coinbase(height),
                             block_time + 100)
        block.rehash()

        block_hex = ToHex(block)
        block_hash = block.getsighash()
        previousblock_hash = int(self.nodes[0].getbestblockhash(), 16)

        self.log.info("Test block : %s" % bytes_to_hex_str(block_hash))

        self.log.info("Testing RPC testproposedblock with valid block")

        assert_equal(self.nodes[0].testproposedblock(block_hex), True)

        self.log.info("Testing RPC combineblocksigs with 3 valid signatures")
        sig0 = self.cKey[0].sign(block_hash)
        sig1 = self.cKey[1].sign(block_hash)
        sig2 = self.cKey[2].sign(block_hash)

        signedBlock = self.nodes[0].combineblocksigs(block_hex, [
            bytes_to_hex_str(sig0),
            bytes_to_hex_str(sig1),
            bytes_to_hex_str(sig2)
        ])

        if (len(signedBlock["warning"])):
            self.log.warning(
                "%s : signatures:%s [%d, %d, %d]" %
                (signedBlock["warning"], [sig0, sig1, sig2],
                 self.cKey[0].verify(block_hash, sig0), self.cKey[1].verify(
                     block_hash, sig1), self.cKey[2].verify(block_hash, sig2)))

        block.solve(self.secret)
        self.nodes[0].p2p.send_blocks_and_test([block],
                                               self.nodes[0],
                                               success=True)
        # combineblocksigs only returns true when signatures are appended and enough
        # are included to pass validation
        assert_equal(signedBlock["complete"], True)
        assert_equal(signedBlock["warning"], "")
        assert_equal(
            len(signedBlock["hex"]),
            len(block_hex) + len(bytes_to_hex_str(sig0)) +
            len(bytes_to_hex_str(sig1)) + len(bytes_to_hex_str(sig2)) + 6)
        #6 is 2 bytes for 3 length of signatures

        self.log.info("Testing RPC combineblocksigs with 1 invalid signature")
        sig0 = bytearray(sig0)
        sig0[2] = 30

        signedBlock = self.nodes[0].combineblocksigs(block_hex, [
            bytes_to_hex_str(sig0),
            bytes_to_hex_str(sig1),
            bytes_to_hex_str(sig2)
        ])

        assert_equal(signedBlock["complete"], True)  #True as threshold is 1
        assert_equal(
            signedBlock["warning"],
            "invalid encoding in signature: Non-canonical DER signature %s One or more signatures were not added to block"
            % (bytes_to_hex_str(sig0)))
        assert_equal(
            len(signedBlock["hex"]),
            len(block_hex) + len(bytes_to_hex_str(sig1)) +
            len(bytes_to_hex_str(sig2)) + 4)

        self.log.info("Testing RPC combineblocksigs with 2 invalid signatures")
        sig1 = bytearray(sig1)
        sig1[2] = 30

        signedBlock = self.nodes[0].combineblocksigs(block_hex, [
            bytes_to_hex_str(sig0),
            bytes_to_hex_str(sig1),
            bytes_to_hex_str(sig2)
        ])

        assert_equal(signedBlock["complete"], True)  #True as threshold is 1
        assert_equal(len(signedBlock["hex"]),
                     len(block_hex) + len(bytes_to_hex_str(sig2)) + 2)

        self.log.info("Testing RPC combineblocksigs with 3 invalid signatures")
        sig2 = bytearray(sig2)
        sig2[2] = 30

        signedBlock = self.nodes[0].combineblocksigs(block_hex, [
            bytes_to_hex_str(sig0),
            bytes_to_hex_str(sig1),
            bytes_to_hex_str(sig2)
        ])

        assert_equal(signedBlock["complete"], False)
        assert_equal(len(signedBlock["hex"]), len(block_hex))

        self.log.info("Testing RPC combineblocksigs  with invalid blocks")
        #invalid block hex
        assert_raises_rpc_error(-22, "Block decode failed",
                                self.nodes[0].combineblocksigs, "0000", [])
        #no signature
        assert_raises_rpc_error(-32602, "Signature list was empty",
                                self.nodes[0].combineblocksigs, block_hex, [])
        #too many signature
        assert_raises_rpc_error(
            -32602, "Too many signatures", self.nodes[0].combineblocksigs,
            block_hex,
            ["00", "00", "00", "00", "00", "00", "00", "00", "00", "00"])

        self.log.info("Testing RPC testproposedblock with old block")
        #invalid block hex
        assert_raises_rpc_error(-22, "Block decode failed",
                                self.nodes[0].testproposedblock, "0000")
        # create invalid block
        height = 103
        invalid_block = create_block(previousblock_hash,
                                     create_coinbase(height), block_time + 110)
        invalid_block.solve(self.secret)
        assert_raises_rpc_error(-25,
                                "proposal was not based on our best chain",
                                self.nodes[0].testproposedblock,
                                ToHex(invalid_block))

        self.log.info("Testing RPC testproposedblock with non standard block")
        # create block with non-standard transaction
        previousblock_hash = int(self.nodes[0].getbestblockhash(), 16)
        height = 103
        nonstd_block = create_block(previousblock_hash,
                                    create_coinbase(height), block_time + 120)
        # 3 of 2 multisig is non standard
        nonstd_script = CScript([
            b'53' + self.pubkeys[0] + self.pubkeys[1] + self.pubkeys[2] +
            b'52ea'
        ])
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(block1.vtx[0].malfixsha256, 0), b""))
        tx.vout.append(CTxOut(50, b'0x51'))
        (sig_hash, err) = SignatureHash(nonstd_script, tx, 0, SIGHASH_ALL)
        signature = self.cKey[0].sign(sig_hash) + b'\x01'  # 0x1 is SIGHASH_ALL
        tx.vin[0].scriptSig = CScript([signature, self.pubkeys[0]])
        tx.rehash()
        #add non-standard tx to block
        nonstd_block.vtx.append(tx)
        nonstd_block.solve(self.secret)
        nonstd_block.hashMerkleRoot = nonstd_block.calc_merkle_root()
        nonstd_block.hashImMerkleRoot = nonstd_block.calc_immutable_merkle_root(
        )
        assert (nonstd_block.is_valid())

        #block is accepted when acceptnonstd flag is set
        assert_equal(
            self.nodes[0].testproposedblock(ToHex(nonstd_block), True), True)

        #block is rejected when acceptnonstd flag is not set
        assert_raises_rpc_error(
            -25, "Block proposal included a non-standard transaction",
            self.nodes[0].testproposedblock, ToHex(nonstd_block), False)
    def prepare_tx_signed_with_sighash(self, address_type,
                                       sighash_rangeproof_aware):
        # Create a tx that is signed with a specific version of the sighash
        # method.
        # If `sighash_rangeproof_aware` is
        # true, the sighash will contain the rangeproofs if SIGHASH_RANGEPROOF is set
        # false, the sighash will NOT contain the rangeproofs if SIGHASH_RANGEPROOF is set

        addr = self.nodes[1].getnewaddress("", address_type)
        assert len(self.nodes[1].getaddressinfo(addr)["confidential_key"]) > 0
        self.nodes[0].sendtoaddress(addr, 1.0)
        self.nodes[0].generate(1)
        self.sync_all()
        utxo = self.nodes[1].listunspent(1, 1, [addr])[0]
        utxo_tx = FromHex(CTransaction(),
                          self.nodes[1].getrawtransaction(utxo["txid"]))
        utxo_spk = CScript(hex_str_to_bytes(utxo["scriptPubKey"]))
        utxo_value = utxo_tx.vout[utxo["vout"]].nValue

        assert len(utxo["amountblinder"]) > 0
        sink_addr = self.nodes[2].getnewaddress()
        unsigned_hex = self.nodes[1].createrawtransaction([{
            "txid": utxo["txid"],
            "vout": utxo["vout"]
        }], {
            sink_addr: 0.9,
            "fee": 0.1
        })
        blinded_hex = self.nodes[1].blindrawtransaction(unsigned_hex)
        blinded_tx = FromHex(CTransaction(), blinded_hex)
        signed_hex = self.nodes[1].signrawtransactionwithwallet(
            blinded_hex)["hex"]
        signed_tx = FromHex(CTransaction(), signed_hex)

        # Make sure that the tx the node produced is always valid.
        test_accept = self.nodes[0].testmempoolaccept([signed_hex])[0]
        assert test_accept["allowed"], "not accepted: {}".format(
            test_accept["reject-reason"])

        # Prepare the keypair we need to re-sign the tx.
        wif = self.nodes[1].dumpprivkey(addr)
        privkey = ECKey()
        privkey.set_wif(wif)
        pubkey = privkey.get_pubkey()

        # Now we need to replace the signature with an equivalent one with the new sighash set.
        hashtype = SIGHASH_ALL | SIGHASH_RANGEPROOF
        if address_type == "legacy":
            if sighash_rangeproof_aware:
                (sighash, _) = SignatureHash(utxo_spk, blinded_tx, 0, hashtype)
            else:
                (sighash, _) = SignatureHash_legacy(utxo_spk, blinded_tx, 0,
                                                    hashtype)
            signature = privkey.sign_ecdsa(sighash) + chr(hashtype).encode(
                'latin-1')
            assert len(signature) <= 0xfc
            assert len(pubkey.get_bytes()) <= 0xfc
            signed_tx.vin[0].scriptSig = CScript(
                struct.pack("<B", len(signature)) + signature +
                struct.pack("<B", len(pubkey.get_bytes())) +
                pubkey.get_bytes())
        elif address_type == "bech32" or address_type == "p2sh-segwit":
            assert signed_tx.wit.vtxinwit[0].scriptWitness.stack[
                1] == pubkey.get_bytes()
            pubkeyhash = hash160(pubkey.get_bytes())
            script = get_p2pkh_script(pubkeyhash)
            if sighash_rangeproof_aware:
                sighash = SegwitVersion1SignatureHash(script, blinded_tx, 0,
                                                      hashtype, utxo_value)
            else:
                sighash = SegwitVersion1SignatureHash_legacy(
                    script, blinded_tx, 0, hashtype, utxo_value)
            signature = privkey.sign_ecdsa(sighash) + chr(hashtype).encode(
                'latin-1')
            signed_tx.wit.vtxinwit[0].scriptWitness.stack[0] = signature
        else:
            assert False

        signed_tx.rehash()
        return signed_tx