예제 #1
0
    def assert_tx_format_also_signed(self, utxo, segwit):
        raw = self.nodes[0].createrawtransaction(
            [{"txid": utxo["txid"], "vout": utxo["vout"]}],
            [{self.unknown_addr: "49.9"}, {"fee": "0.1"}]
        )

        unsigned_decoded = self.nodes[0].decoderawtransaction(raw)
        assert_equal(len(unsigned_decoded["vin"]), 1)
        assert('txinwitness' not in unsigned_decoded["vin"][0])

        # Cross-check python serialization
        tx = CTransaction()
        tx.deserialize(BytesIO(hex_str_to_bytes(raw)))
        assert_equal(tx.vin[0].prevout.hash, int("0x"+utxo["txid"], 0))
        assert_equal(len(tx.vin), len(unsigned_decoded["vin"]))
        assert_equal(len(tx.vout), len(unsigned_decoded["vout"]))
        # assert re-encoding
        serialized = bytes_to_hex_str(tx.serialize())
        assert_equal(serialized, raw)

        # Now sign and repeat tests
        signed_raw = self.nodes[0].signrawtransactionwithwallet(raw)["hex"]
        signed_decoded = self.nodes[0].decoderawtransaction(signed_raw)
        assert_equal(len(signed_decoded["vin"]), 1)
        assert(("txinwitness" in signed_decoded["vin"][0]) == segwit)

        # Cross-check python serialization
        tx = CTransaction()
        tx.deserialize(BytesIO(hex_str_to_bytes(signed_raw)))
        assert_equal(tx.vin[0].prevout.hash, int("0x"+utxo["txid"], 0))
        assert_equal(bytes_to_hex_str(tx.vin[0].scriptSig), signed_decoded["vin"][0]["scriptSig"]["hex"])
        # test witness
        if segwit:
            wit_decoded = signed_decoded["vin"][0]["txinwitness"]
            for i in range(len(wit_decoded)):
                assert_equal(bytes_to_hex_str(tx.wit.vtxinwit[0].scriptWitness.stack[i]), wit_decoded[i])
        # assert re-encoding
        serialized = bytes_to_hex_str(tx.serialize())
        assert_equal(serialized, signed_raw)

        txid = self.nodes[0].sendrawtransaction(serialized)
        nodetx = self.nodes[0].getrawtransaction(txid, 1)
        assert_equal(nodetx["txid"], tx.rehash())
        # cross-check wtxid report from node
        wtxid = bytes_to_hex_str(ser_uint256(tx.calc_sha256(True))[::-1])
        assert_equal(nodetx["wtxid"], wtxid)
        assert_equal(nodetx["hash"], wtxid)

        # witness hash stuff
        assert_equal(nodetx["withash"], tx.calc_witness_hash())
        return (txid, wtxid)
예제 #2
0
  def buildDummySegwitNameUpdate (self, name, value, addr):
    """
    Builds a transaction that updates the given name to the given value and
    address.  We assume that the name is at a native segwit script.  The witness
    of the transaction will be set to two dummy stack elements so that the
    program itself is "well-formed" even if it won't execute successfully.
    """

    data = self.node.name_show (name)
    u = self.findUnspent (Decimal ('0.01'))
    ins = [data, u]
    outs = {addr: Decimal ('0.01')}

    txHex = self.node.createrawtransaction (ins, outs)
    nameOp = {"op": "name_update", "name": name, "value": value}
    txHex = self.node.namerawtransaction (txHex, 0, nameOp)['hex']
    txHex = self.node.signrawtransactionwithwallet (txHex)['hex']

    tx = CTransaction ()
    tx.deserialize (io.BytesIO (hex_str_to_bytes (txHex)))
    tx.wit = CTxWitness ()
    tx.wit.vtxinwit.append (CTxInWitness ())
    tx.wit.vtxinwit[0].scriptWitness = CScriptWitness ()
    tx.wit.vtxinwit[0].scriptWitness.stack = [b"dummy"] * 2
    txHex = tx.serialize ().hex ()

    return txHex
예제 #3
0
        def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001*COIN, _total_txs=None):
            if _total_txs is None:
                _total_txs = [0]
            if _total_txs[0] >= max_txs:
                return

            txout_value = (initial_value - fee) // tree_width
            if txout_value < fee:
                return

            vout = [CTxOut(txout_value, CScript([i+1]))
                    for i in range(tree_width)]
            tx = CTransaction()
            tx.vin = [CTxIn(prevout, nSequence=0)]
            tx.vout = vout
            tx_hex = txToHex(tx)

            assert(len(tx.serialize()) < 100000)
            txid = self.nodes[0].sendrawtransaction(tx_hex, True)
            yield tx
            _total_txs[0] += 1

            txid = int(txid, 16)

            for i, txout in enumerate(tx.vout):
                for x in branch(COutPoint(txid, i), txout_value,
                                  max_txs,
                                  tree_width=tree_width, fee=fee,
                                  _total_txs=_total_txs):
                    yield x
예제 #4
0
  def setScriptSigOps (self, txHex, ind, scriptSigOps):
    """
    Update the given hex transaction by setting the scriptSig for the
    input with the given index.
    """

    tx = CTransaction ()
    tx.deserialize (io.BytesIO (hex_str_to_bytes (txHex)))
    tx.vin[ind].scriptSig = CScript (scriptSigOps)

    return tx.serialize ().hex ()
예제 #5
0
    def sign_stake_tx(self, block, stake_in_value, fZPoS=False):
        ''' signs a coinstake transaction
        :param      block:           (CBlock) block with stake to sign
                    stake_in_value:  (int) staked amount
                    fZPoS:           (bool) zerocoin stake
        :return:    stake_tx_signed: (CTransaction) signed tx
        '''
        self.block_sig_key = CECKey()

        if fZPoS:
            self.log.info("Signing zPoS stake...")
            # Create raw zerocoin stake TX (signed)
            raw_stake = self.node.createrawzerocoinstake(block.prevoutStake)
            stake_tx_signed_raw_hex = raw_stake["hex"]
            # Get stake TX private key to sign the block with
            stake_pkey = raw_stake["private-key"]
            self.block_sig_key.set_compressed(True)
            self.block_sig_key.set_secretbytes(bytes.fromhex(stake_pkey))

        else:
            # Create a new private key and get the corresponding public key
            self.block_sig_key.set_secretbytes(hash256(pack('<I', 0xffff)))
            pubkey = self.block_sig_key.get_pubkey()
            # Create the raw stake TX (unsigned)
            scriptPubKey = CScript([pubkey, OP_CHECKSIG])
            outNValue = int(stake_in_value + 2*COIN)
            stake_tx_unsigned = CTransaction()
            stake_tx_unsigned.nTime = block.nTime
            stake_tx_unsigned.vin.append(CTxIn(block.prevoutStake))
            stake_tx_unsigned.vin[0].nSequence = 0xffffffff
            stake_tx_unsigned.vout.append(CTxOut())
            stake_tx_unsigned.vout.append(CTxOut(outNValue, scriptPubKey))
            # Sign the stake TX
            stake_tx_signed_raw_hex = self.node.signrawtransaction(bytes_to_hex_str(stake_tx_unsigned.serialize()))['hex']

        # Deserialize the signed raw tx into a CTransaction object and return it
        stake_tx_signed = CTransaction()
        stake_tx_signed.deserialize(BytesIO(hex_str_to_bytes(stake_tx_signed_raw_hex)))
        return stake_tx_signed
예제 #6
0
    def test_multiple_children(self):
        node = self.nodes[0]

        self.log.info(
            "Testmempoolaccept a package in which a transaction has two children within the package"
        )
        first_coin = self.coins.pop()
        value = (first_coin["amount"] - Decimal("0.0002")
                 ) / 2  # Deduct reasonable fee and make 2 outputs
        inputs = [{"txid": first_coin["txid"], "vout": 0}]
        outputs = [{self.address: value}, {ADDRESS_BCRT1_P2WSH_OP_TRUE: value}]
        rawtx = node.createrawtransaction(inputs, outputs)

        parent_signed = node.signrawtransactionwithkey(hexstring=rawtx,
                                                       privkeys=self.privkeys)
        parent_tx = CTransaction()
        assert parent_signed["complete"]
        parent_tx.deserialize(BytesIO(hex_str_to_bytes(parent_signed["hex"])))
        parent_txid = parent_tx.rehash()
        assert node.testmempoolaccept([parent_signed["hex"]])[0]["allowed"]

        parent_locking_script_a = parent_tx.vout[0].scriptPubKey.hex()
        child_value = value - Decimal("0.0001")

        # Child A
        (_, tx_child_a_hex, _,
         _) = self.chain_transaction(parent_txid, child_value, 0,
                                     parent_locking_script_a)
        assert not node.testmempoolaccept([tx_child_a_hex])[0]["allowed"]

        # Child B
        rawtx_b = node.createrawtransaction([{
            "txid": parent_txid,
            "vout": 1
        }], {self.address: child_value})
        tx_child_b = CTransaction()
        tx_child_b.deserialize(BytesIO(hex_str_to_bytes(rawtx_b)))
        tx_child_b.wit.vtxinwit = [CTxInWitness()]
        tx_child_b.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
        tx_child_b_hex = tx_child_b.serialize().hex()
        assert not node.testmempoolaccept([tx_child_b_hex])[0]["allowed"]

        self.log.info(
            "Testmempoolaccept with entire package, should work with children in either order"
        )
        testres_multiple_ab = node.testmempoolaccept(
            rawtxs=[parent_signed["hex"], tx_child_a_hex, tx_child_b_hex])
        testres_multiple_ba = node.testmempoolaccept(
            rawtxs=[parent_signed["hex"], tx_child_b_hex, tx_child_a_hex])
        assert all([
            testres["allowed"]
            for testres in testres_multiple_ab + testres_multiple_ba
        ])

        testres_single = []
        # Test accept and then submit each one individually, which should be identical to package testaccept
        for rawtx in [parent_signed["hex"], tx_child_a_hex, tx_child_b_hex]:
            testres = node.testmempoolaccept([rawtx])
            testres_single.append(testres[0])
            # Submit the transaction now so its child should have no problem validating
            node.sendrawtransaction(rawtx)
        assert_equal(testres_single, testres_multiple_ab)
예제 #7
0
    def decoderawtransaction_asm_sighashtype(self):
        """Test decoding scripts via RPC command "decoderawtransaction".

        This test is in with the "decodescript" tests because they are testing the same "asm" script decodes.
        """

        # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output
        tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm'])

        # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs.
        # it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc
        # verify that we have not altered scriptPubKey decoding.
        tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0', rpc_result['txid'])
        assert_equal('0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae', rpc_result['vin'][0]['scriptSig']['asm'])
        assert_equal('OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])
        assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])
        txSave = CTransaction()
        txSave.deserialize(BytesIO(hex_str_to_bytes(tx)))

        # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type
        tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm'])

        # verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks
        tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])
        assert_equal('OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])

        # some more full transaction tests of varying specific scriptSigs. used instead of
        # tests in decodescript_script_sig because the decodescript RPC is specifically
        # for working on scriptPubKeys (argh!).
        push_signature = txSave.vin[0].scriptSig.hex()[2:(0x48*2+4)]
        signature = push_signature[2:]
        der_signature = signature[:-2]
        signature_sighash_decoded = der_signature + '[ALL]'
        signature_2 = der_signature + '82'
        push_signature_2 = '48' + signature_2
        signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]'

        # 1) P2PK scriptSig
        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature)
        rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
        assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])

        # make sure that the sighash decodes come out correctly for a more complex / lesser used case.
        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature_2)
        rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
        assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])

        # 2) multisig scriptSig
        txSave.vin[0].scriptSig = hex_str_to_bytes('00' + push_signature + push_signature_2)
        rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
        assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])

        # 3) test a scriptSig that contains more than push operations.
        # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it.
        txSave.vin[0].scriptSig = hex_str_to_bytes('6a143011020701010101010101020601010101010101')
        rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
        assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm'])
예제 #8
0
    def run_test(self):
        node = self.nodes[0]

        self.log.info('Start with empty mempool, and 200 blocks')
        self.mempool_size = 0
        assert_equal(node.getblockcount(), 200)
        assert_equal(node.getmempoolinfo()['size'], self.mempool_size)
        coins = node.listunspent()

        self.log.info('Should not accept garbage to testmempoolaccept')
        assert_raises_rpc_error(-3, 'Expected type array, got string', lambda: node.testmempoolaccept(rawtxs='ff00baar'))
        assert_raises_rpc_error(-8, 'Array must contain exactly one raw transaction for now', lambda: node.testmempoolaccept(rawtxs=['ff00baar', 'ff22']))
        assert_raises_rpc_error(-22, 'TX decode failed', lambda: node.testmempoolaccept(rawtxs=['ff00baar']))

        self.log.info('A transaction already in the blockchain')
        coin = coins.pop()  # Pick a random coin(base) to spend
        raw_tx_in_block = node.signrawtransactionwithwallet(node.createrawtransaction(
            inputs=[{'txid': coin['txid'], 'vout': coin['vout']}],
            outputs=[{node.getnewaddress(): 0.3}, {node.getnewaddress(): 49}],
        ))['hex']
        txid_in_block = node.sendrawtransaction(hexstring=raw_tx_in_block, maxfeerate=0)
        node.generate(1)
        self.mempool_size = 0
        self.check_mempool_result(
            result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': '18: txn-already-known'}],
            rawtxs=[raw_tx_in_block],
        )

        self.log.info('A transaction not in the mempool')
        fee = 0.00000700
        raw_tx_0 = node.signrawtransactionwithwallet(node.createrawtransaction(
            inputs=[{"txid": txid_in_block, "vout": 0, "sequence": BIP125_SEQUENCE_NUMBER}],  # RBF is used later
            outputs=[{node.getnewaddress(): 0.3 - fee}],
        ))['hex']
        tx = CTransaction()
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        txid_0 = tx.rehash()
        self.check_mempool_result(
            result_expected=[{'txid': txid_0, 'allowed': True}],
            rawtxs=[raw_tx_0],
        )

        self.log.info('A final transaction not in the mempool')
        coin = coins.pop()  # Pick a random coin(base) to spend
        raw_tx_final = node.signrawtransactionwithwallet(node.createrawtransaction(
            inputs=[{'txid': coin['txid'], 'vout': coin['vout'], "sequence": 0xffffffff}],  # SEQUENCE_FINAL
            outputs=[{node.getnewaddress(): 0.025}],
            locktime=node.getblockcount() + 2000,  # Can be anything
        ))['hex']
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_final)))
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': True}],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )
        node.sendrawtransaction(hexstring=raw_tx_final, maxfeerate=0)
        self.mempool_size += 1

        self.log.info('A transaction in the mempool')
        node.sendrawtransaction(hexstring=raw_tx_0)
        self.mempool_size += 1
        self.check_mempool_result(
            result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': '18: txn-already-in-mempool'}],
            rawtxs=[raw_tx_0],
        )

        self.log.info('A transaction that replaces a mempool transaction')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        tx.vout[0].nValue -= int(fee * COIN)  # Double the fee
        tx.vin[0].nSequence = BIP125_SEQUENCE_NUMBER + 1  # Now, opt out of RBF
        raw_tx_0 = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        txid_0 = tx.rehash()
        self.check_mempool_result(
            result_expected=[{'txid': txid_0, 'allowed': True}],
            rawtxs=[raw_tx_0],
        )

        self.log.info('A transaction that conflicts with an unconfirmed tx')
        # Send the transaction that replaces the mempool transaction and opts out of replaceability
        node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
        # take original raw_tx_0
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        tx.vout[0].nValue -= int(4 * fee * COIN)  # Set more fee
        # skip re-signing the tx
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '18: txn-mempool-conflict'}],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )

        self.log.info('A transaction with missing inputs, that never existed')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        tx.vin[0].prevout = COutPoint(hash=int('ff' * 32, 16), n=14)
        # skip re-signing the tx
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'missing-inputs'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction with missing inputs, that existed once in the past')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        tx.vin[0].prevout.n = 1  # Set vout to 1, to spend the other outpoint (49 coins) of the in-chain-tx we want to double spend
        raw_tx_1 = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
        txid_1 = node.sendrawtransaction(hexstring=raw_tx_1, maxfeerate=0)
        # Now spend both to "clearly hide" the outputs, ie. remove the coins from the utxo set by spending them
        raw_tx_spend_both = node.signrawtransactionwithwallet(node.createrawtransaction(
            inputs=[
                {'txid': txid_0, 'vout': 0},
                {'txid': txid_1, 'vout': 0},
            ],
            outputs=[{node.getnewaddress(): 0.1}]
        ))['hex']
        txid_spend_both = node.sendrawtransaction(hexstring=raw_tx_spend_both, maxfeerate=0)
        node.generate(1)
        self.mempool_size = 0
        # Now see if we can add the coins back to the utxo set by sending the exact txs again
        self.check_mempool_result(
            result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': 'missing-inputs'}],
            rawtxs=[raw_tx_0],
        )
        self.check_mempool_result(
            result_expected=[{'txid': txid_1, 'allowed': False, 'reject-reason': 'missing-inputs'}],
            rawtxs=[raw_tx_1],
        )

        self.log.info('Create a signed "reference" tx for later use')
        raw_tx_reference = node.signrawtransactionwithwallet(node.createrawtransaction(
            inputs=[{'txid': txid_spend_both, 'vout': 0}],
            outputs=[{node.getnewaddress(): 0.05}],
        ))['hex']
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        # Reference tx should be valid on itself
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': True}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction with no outputs')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout = []
        # Skip re-signing the transaction for context independent checks from now on
        # tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransactionwithwallet(tx.serialize().hex())['hex'])))
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-empty'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A really large transaction')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_BASE_SIZE / len(tx.vin[0].serialize()))
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-oversize'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction with negative output value')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0].nValue *= -1
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-negative'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction with too large output value')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0].nValue = 21000000 * COIN + 1
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-toolarge'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction with too large sum of output values')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout = [tx.vout[0]] * 2
        tx.vout[0].nValue = 21000000 * COIN
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-txouttotal-toolarge'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction with duplicate inputs')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin = [tx.vin[0]] * 2
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-inputs-duplicate'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A coinbase transaction')
        # Pick the input of the first tx we signed, so it has to be a coinbase tx
        raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid'])
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_coinbase_spent)))
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: coinbase'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('Some nonstandard transactions')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.nVersion = 3  # A version currently non-standard
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: version'}],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0].scriptPubKey = CScript([OP_0])  # Some non-standard script
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptpubkey'}],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin[0].scriptSig = CScript([OP_HASH160])  # Some not-pushonly scriptSig
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-not-pushonly'}],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        output_p2sh_burn = CTxOut(nValue=540, scriptPubKey=CScript([OP_HASH160, hash160(b'burn'), OP_EQUAL]))
        num_scripts = 100000 // len(output_p2sh_burn.serialize())  # Use enough outputs to make the tx too large for our policy
        tx.vout = [output_p2sh_burn] * num_scripts
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: tx-size'}],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0] = output_p2sh_burn
        tx.vout[0].nValue -= 1  # Make output smaller, such that it is dust for our policy
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: dust'}],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
        tx.vout = [tx.vout[0]] * 2
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: multi-op-return'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A timelocked transaction')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin[0].nSequence -= 1  # Should be non-max, so locktime is not ignored
        tx.nLockTime = node.getblockcount() + 1
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-final'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction that is locked by BIP68 sequence logic')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin[0].nSequence = 2  # We could include it in the second block mined from now, but not the very next one
        # Can skip re-signing the tx because of early rejection
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-BIP68-final'}],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )
예제 #9
0
    def _test_moveWithCurrency(self):
        """
    Sends currency to predefined addresses together with a move and checks
    the "out" field produced by the notifications.
    """

        self.log.info("Sending move with currency...")

        addr1 = self.node.getnewaddress()
        addr2 = "dHNvNaqcD7XPDnoRjAoyfcMpHRi5upJD7p"

        # Send a move and spend coins in the same transaction.  We use a raw
        # transaction, so that we can actually send *two* outputs to the *same*
        # address.  This should work, and return it only once in the notification
        # with the total amount.  We use amounts with precision down to satoshis
        # to check this works correctly.

        hex1 = self.node.getaddressinfo(addr1)["scriptPubKey"]
        hex2 = self.node.getaddressinfo(addr2)["scriptPubKey"]
        scr1 = CScript(hex_str_to_bytes(hex1))
        scr2 = CScript(hex_str_to_bytes(hex2))

        tx = CTransaction()
        name = self.node.name_show("p/x")
        tx.vin.append(CTxIn(COutPoint(int(name["txid"], 16), name["vout"])))
        tx.vout.append(CTxOut(12345678, scr1))
        tx.vout.append(CTxOut(142424242, scr2))
        tx.vout.append(CTxOut(COIN, scr1))
        tx.vout.append(CTxOut(COIN // 2, CScript([OP_TRUE])))
        tx.vout.append(CTxOut(COIN // 100, scr1))
        rawtx = tx.serialize().hex()

        nameOp = {
            "op": "name_update",
            "name": "p/x",
            "value": json.dumps({"g": {
                "a": "move"
            }}),
        }
        rawtx = self.node.namerawtransaction(rawtx, 4, nameOp)["hex"]

        rawtx = self.node.fundrawtransaction(rawtx)["hex"]
        signed = self.node.signrawtransactionwithwallet(rawtx)
        assert signed["complete"]
        txid = self.node.sendrawtransaction(signed["hex"])
        self.node.generate(1)

        _, data = self.games["a"].receive()
        assert_equal(len(data["moves"]), 1)
        assertMove(data["moves"][0], txid, "x", "move")
        assert_equal(data["moves"][0]["burnt"], 0)
        out = data["moves"][0]["out"]
        assert_equal(len(out), 3)
        quant = Decimal('1.00000000')
        assert_equal(
            Decimal(out[addr1]).quantize(quant), Decimal('1.12345678'))
        assert_equal(
            Decimal(out[addr2]).quantize(quant), Decimal('1.42424242'))

        _, data = self.games["b"].receive()
        assert_equal(data["moves"], [])
예제 #10
0
    def test_desc_size_limits(self):
        """Create 3 mempool transactions and 2 package transactions (25KvB each):
              Ma
             ^ ^
            Mb  Mc
           ^     ^
          Pd      Pe
        The top ancestor in the package exceeds descendant size limits but only if the in-mempool
        and in-package descendants are all considered together.
        """
        node = self.nodes[0]
        assert_equal(0, node.getmempoolinfo()["size"])
        target_weight = 21 * 1000 * WITNESS_SCALE_FACTOR
        high_fee = Decimal("0.0021") # 10 sats/vB
        self.log.info("Check that in-mempool and in-package descendant sizes are calculated properly in packages")
        # Top parent in mempool, Ma
        first_coin = self.coins.pop()
        parent_value = (first_coin["amount"] - high_fee) / 2 # Deduct fee and make 2 outputs
        inputs = [{"txid": first_coin["txid"], "vout": 0}]
        outputs = [{self.address : parent_value}, {ADDRESS_BCRT1_P2WSH_OP_TRUE:  parent_value}]
        rawtx = node.createrawtransaction(inputs, outputs)
        parent_tx = bulk_transaction(tx_from_hex(rawtx), node, target_weight, self.privkeys)
        node.sendrawtransaction(parent_tx.serialize().hex())

        package_hex = []
        for j in range(2): # Two legs (left and right)
            # Mempool transaction (Mb and Mc)
            mempool_tx = CTransaction()
            spk = parent_tx.vout[j].scriptPubKey.hex()
            value = Decimal(parent_tx.vout[j].nValue) / COIN
            txid = parent_tx.rehash()
            prevtxs = [{
                "txid": txid,
                "vout": j,
                "scriptPubKey": spk,
                "amount": value,
            }]
            if j == 0: # normal key
                (tx_small, _, _, _) = make_chain(node, self.address, self.privkeys, txid, value, j, spk, high_fee)
                mempool_tx = bulk_transaction(tx_small, node, target_weight, self.privkeys, prevtxs)
            else: # OP_TRUE
                inputs = [{"txid": txid, "vout": 1}]
                outputs = {self.address: value - high_fee}
                small_tx = tx_from_hex(node.createrawtransaction(inputs, outputs))
                mempool_tx = bulk_transaction(small_tx, node, target_weight, None, prevtxs)
            node.sendrawtransaction(mempool_tx.serialize().hex())

            # Package transaction (Pd and Pe)
            spk = mempool_tx.vout[0].scriptPubKey.hex()
            value = Decimal(mempool_tx.vout[0].nValue) / COIN
            txid = mempool_tx.rehash()
            (tx_small, _, _, _) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk, high_fee)
            prevtxs = [{
                "txid": txid,
                "vout": 0,
                "scriptPubKey": spk,
                "amount": value,
            }]
            package_tx = bulk_transaction(tx_small, node, target_weight, self.privkeys, prevtxs)
            package_hex.append(package_tx.serialize().hex())

        assert_equal(3, node.getmempoolinfo()["size"])
        assert_equal(2, len(package_hex))
        testres_too_heavy = node.testmempoolaccept(rawtxs=package_hex)
        for txres in testres_too_heavy:
            assert_equal(txres["package-error"], "package-mempool-limits")

        # Clear mempool and check that the package passes now
        node.generate(1)
        assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
예제 #11
0
    def run_test(self):
        node = self.nodes[0]

        self.log.info('Start with empty mempool, and 200 blocks')
        self.mempool_size = 0
        assert_equal(node.getblockcount(), 200)
        assert_equal(node.getmempoolinfo()['size'], self.mempool_size)
        coins = node.listunspent()

        self.log.info('Should not accept garbage to testmempoolaccept')
        assert_raises_rpc_error(-3, 'Expected type array, got string', lambda: node.testmempoolaccept(rawtxs='ff00baar'))
        assert_raises_rpc_error(-8, 'Array must contain exactly one raw transaction for now', lambda: node.testmempoolaccept(rawtxs=['ff00baar', 'ff22']))
        assert_raises_rpc_error(-22, 'TX decode failed', lambda: node.testmempoolaccept(rawtxs=['ff00baar']))

        self.log.info('A transaction already in the blockchain')
        coin = coins.pop()  # Pick a random coin(base) to spend
        raw_tx_in_block = node.signrawtransactionwithwallet(node.createrawtransaction(
            inputs=[{'txid': coin['txid'], 'vout': coin['vout']}],
            outputs=[{node.getnewaddress(): 0.3}, {node.getnewaddress(): 49}],
        ))['hex']
        txid_in_block = node.sendrawtransaction(hexstring=raw_tx_in_block, maxfeerate=0)
        node.generate(1)
        self.mempool_size = 0
        self.check_mempool_result(
            result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': 'txn-already-known'}],
            rawtxs=[raw_tx_in_block],
        )

        self.log.info('A transaction not in the mempool')
        fee = 0.00000700
        raw_tx_0 = node.signrawtransactionwithwallet(node.createrawtransaction(
            inputs=[{"txid": txid_in_block, "vout": 0, "sequence": BIP125_SEQUENCE_NUMBER}],  # RBF is used later
            outputs=[{node.getnewaddress(): 0.3 - fee}],
        ))['hex']
        tx = CTransaction()
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        txid_0 = tx.rehash()
        self.check_mempool_result(
            result_expected=[{'txid': txid_0, 'allowed': True}],
            rawtxs=[raw_tx_0],
        )

        self.log.info('A final transaction not in the mempool')
        coin = coins.pop()  # Pick a random coin(base) to spend
        raw_tx_final = node.signrawtransactionwithwallet(node.createrawtransaction(
            inputs=[{'txid': coin['txid'], 'vout': coin['vout'], "sequence": 0xffffffff}],  # SEQUENCE_FINAL
            outputs=[{node.getnewaddress(): 0.025}],
            locktime=node.getblockcount() + 2000,  # Can be anything
        ))['hex']
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_final)))
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': True}],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )
        node.sendrawtransaction(hexstring=raw_tx_final, maxfeerate=0)
        self.mempool_size += 1

        self.log.info('A transaction in the mempool')
        node.sendrawtransaction(hexstring=raw_tx_0)
        self.mempool_size += 1
        self.check_mempool_result(
            result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': 'txn-already-in-mempool'}],
            rawtxs=[raw_tx_0],
        )

        self.log.info('A transaction that replaces a mempool transaction')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        tx.vout[0].nValue -= int(fee * COIN)  # Double the fee
        tx.vin[0].nSequence = BIP125_SEQUENCE_NUMBER + 1  # Now, opt out of RBF
        raw_tx_0 = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        txid_0 = tx.rehash()
        self.check_mempool_result(
            result_expected=[{'txid': txid_0, 'allowed': True}],
            rawtxs=[raw_tx_0],
        )

        self.log.info('A transaction that conflicts with an unconfirmed tx')
        # Send the transaction that replaces the mempool transaction and opts out of replaceability
        node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
        # take original raw_tx_0
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        tx.vout[0].nValue -= int(4 * fee * COIN)  # Set more fee
        # skip re-signing the tx
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'txn-mempool-conflict'}],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )

        self.log.info('A transaction with missing inputs, that never existed')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        tx.vin[0].prevout = COutPoint(hash=int('ff' * 32, 16), n=14)
        # skip re-signing the tx
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'missing-inputs'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction with missing inputs, that existed once in the past')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
        tx.vin[0].prevout.n = 1  # Set vout to 1, to spend the other outpoint (49 coins) of the in-chain-tx we want to double spend
        raw_tx_1 = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
        txid_1 = node.sendrawtransaction(hexstring=raw_tx_1, maxfeerate=0)
        # Now spend both to "clearly hide" the outputs, ie. remove the coins from the utxo set by spending them
        raw_tx_spend_both = node.signrawtransactionwithwallet(node.createrawtransaction(
            inputs=[
                {'txid': txid_0, 'vout': 0},
                {'txid': txid_1, 'vout': 0},
            ],
            outputs=[{node.getnewaddress(): 0.1}]
        ))['hex']
        txid_spend_both = node.sendrawtransaction(hexstring=raw_tx_spend_both, maxfeerate=0)
        node.generate(1)
        self.mempool_size = 0
        # Now see if we can add the coins back to the utxo set by sending the exact txs again
        self.check_mempool_result(
            result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': 'missing-inputs'}],
            rawtxs=[raw_tx_0],
        )
        self.check_mempool_result(
            result_expected=[{'txid': txid_1, 'allowed': False, 'reject-reason': 'missing-inputs'}],
            rawtxs=[raw_tx_1],
        )

        self.log.info('Create a signed "reference" tx for later use')
        raw_tx_reference = node.signrawtransactionwithwallet(node.createrawtransaction(
            inputs=[{'txid': txid_spend_both, 'vout': 0}],
            outputs=[{node.getnewaddress(): 0.05}],
        ))['hex']
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        # Reference tx should be valid on itself
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': True}],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )

        self.log.info('A transaction with no outputs')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout = []
        # Skip re-signing the transaction for context independent checks from now on
        # tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransactionwithwallet(tx.serialize().hex())['hex'])))
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-empty'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A really large transaction')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_BASE_SIZE / len(tx.vin[0].serialize()))
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-oversize'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction with negative output value')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0].nValue *= -1
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-negative'}],
            rawtxs=[tx.serialize().hex()],
        )

        # The following two validations prevent overflow of the output amounts (see CVE-2010-5139).
        self.log.info('A transaction with too large output value')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0].nValue = MAX_MONEY + 1
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-toolarge'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction with too large sum of output values')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout = [tx.vout[0]] * 2
        tx.vout[0].nValue = MAX_MONEY
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-txouttotal-toolarge'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction with duplicate inputs')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin = [tx.vin[0]] * 2
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-inputs-duplicate'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A coinbase transaction')
        # Pick the input of the first tx we signed, so it has to be a coinbase tx
        raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid'])
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_coinbase_spent)))
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'coinbase'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('Some nonstandard transactions')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.nVersion = 3  # A version currently non-standard
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'version'}],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0].scriptPubKey = CScript([OP_0])  # Some non-standard script
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptpubkey'}],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        key = ECKey()
        key.generate()
        pubkey = key.get_pubkey().get_bytes()
        tx.vout[0].scriptPubKey = CScript([OP_2, pubkey, pubkey, pubkey, OP_3, OP_CHECKMULTISIG])  # Some bare multisig script (2-of-3)
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bare-multisig'}],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin[0].scriptSig = CScript([OP_HASH160])  # Some not-pushonly scriptSig
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-not-pushonly'}],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-size'}],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        output_p2sh_burn = CTxOut(nValue=540, scriptPubKey=CScript([OP_HASH160, hash160(b'burn'), OP_EQUAL]))
        num_scripts = 100000 // len(output_p2sh_burn.serialize())  # Use enough outputs to make the tx too large for our policy
        tx.vout = [output_p2sh_burn] * num_scripts
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'tx-size'}],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0] = output_p2sh_burn
        tx.vout[0].nValue -= 1  # Make output smaller, such that it is dust for our policy
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'dust'}],
            rawtxs=[tx.serialize().hex()],
        )
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
        tx.vout = [tx.vout[0]] * 2
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'multi-op-return'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A timelocked transaction')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin[0].nSequence -= 1  # Should be non-max, so locktime is not ignored
        tx.nLockTime = node.getblockcount() + 1
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-final'}],
            rawtxs=[tx.serialize().hex()],
        )

        self.log.info('A transaction that is locked by BIP68 sequence logic')
        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
        tx.vin[0].nSequence = 2  # We could include it in the second block mined from now, but not the very next one
        # Can skip re-signing the tx because of early rejection
        self.check_mempool_result(
            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-BIP68-final'}],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )
예제 #12
0
    def run_test(self):
        self.log.info(
            'prepare some coins for multiple *rawtransaction commands')
        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[0].generate(101)
        self.sync_all()
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.5)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0)
        self.sync_all()
        self.nodes[0].generate(5)
        self.sync_all()

        self.log.info(
            'Test getrawtransaction on genesis block coinbase returns an error'
        )
        block = self.nodes[0].getblock(self.nodes[0].getblockhash(0))
        assert_raises_rpc_error(
            -5,
            "The genesis block coinbase is not considered an ordinary transaction",
            self.nodes[0].getrawtransaction, block['merkleroot'])

        self.log.info(
            'Check parameter types and required parameters of createrawtransaction'
        )
        # Test `createrawtransaction` required parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction)
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [])

        # Test `createrawtransaction` invalid extra parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [], {}, 0,
                                'foo')

        # Test `createrawtransaction` invalid `inputs`
        txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'
        assert_raises_rpc_error(-3, "Expected type array",
                                self.nodes[0].createrawtransaction, 'foo', {})
        assert_raises_rpc_error(-1, "JSON value is not an object as expected",
                                self.nodes[0].createrawtransaction, ['foo'],
                                {})
        assert_raises_rpc_error(-1, "JSON value is not a string as expected",
                                self.nodes[0].createrawtransaction, [{}], {})
        assert_raises_rpc_error(
            -8, "txid must be of length 64 (not 3, for 'foo')",
            self.nodes[0].createrawtransaction, [{
                'txid': 'foo'
            }], {})
        assert_raises_rpc_error(
            -8,
            "txid must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')",
            self.nodes[0].createrawtransaction, [{
                'txid':
                'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844'
            }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid
                                }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, vout must be a number",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid,
                                    'vout': 'foo'
                                }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, vout must be positive",
                                self.nodes[0].createrawtransaction, [{
                                    'txid': txid,
                                    'vout': -1
                                }], {})
        assert_raises_rpc_error(
            -8, "Invalid parameter, sequence number is out of range",
            self.nodes[0].createrawtransaction, [{
                'txid': txid,
                'vout': 0,
                'sequence': -1
            }], {})

        # Test `createrawtransaction` invalid `outputs`
        address = self.nodes[0].getnewaddress()
        address2 = self.nodes[0].getnewaddress()
        assert_raises_rpc_error(-1, "JSON value is not an array as expected",
                                self.nodes[0].createrawtransaction, [], 'foo')
        # Should not throw for backwards compatibility
        self.nodes[0].createrawtransaction(inputs=[], outputs={})
        self.nodes[0].createrawtransaction(inputs=[], outputs=[])
        assert_raises_rpc_error(-8, "Data must be hexadecimal string",
                                self.nodes[0].createrawtransaction, [],
                                {'data': 'foo'})
        assert_raises_rpc_error(-5, "Invalid Bitcoin address",
                                self.nodes[0].createrawtransaction, [],
                                {'foo': 0})
        assert_raises_rpc_error(-3, "Invalid amount",
                                self.nodes[0].createrawtransaction, [],
                                {address: 'foo'})
        assert_raises_rpc_error(-3, "Amount out of range",
                                self.nodes[0].createrawtransaction, [],
                                {address: -1})
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: {}".format(address),
            self.nodes[0].createrawtransaction, [],
            multidict([(address, 1), (address, 1)]))
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: {}".format(address),
            self.nodes[0].createrawtransaction, [], [{
                address: 1
            }, {
                address: 1
            }])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
                                self.nodes[0].createrawtransaction, [],
                                [{
                                    "data": 'aa'
                                }, {
                                    "data": "bb"
                                }])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
                                self.nodes[0].createrawtransaction, [],
                                multidict([("data", 'aa'), ("data", "bb")]))
        assert_raises_rpc_error(
            -8,
            "Invalid parameter, key-value pair must contain exactly one key",
            self.nodes[0].createrawtransaction, [], [{
                'a': 1,
                'b': 2
            }])
        assert_raises_rpc_error(
            -8, "Invalid parameter, key-value pair not an object as expected",
            self.nodes[0].createrawtransaction, [],
            [['key-value pair1'], ['2']])

        # Test `createrawtransaction` invalid `locktime`
        assert_raises_rpc_error(-3, "Expected type number",
                                self.nodes[0].createrawtransaction, [], {},
                                'foo')
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {}, -1)
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {},
                                4294967296)

        self.log.info(
            'Check that createrawtransaction accepts an array and object as outputs'
        )
        tx = CTransaction()
        # One output
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }], outputs={address: 99}))))
        assert_equal(len(tx.vout), 1)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }]),
        )
        # Two outputs
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }],
                    outputs=OrderedDict([(address, 99), (address2, 99)])))))
        assert_equal(len(tx.vout), 2)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   address2: 99
                                               }]),
        )
        # Multiple mixed outputs
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }],
                    outputs=multidict([(address, 99), (address2, 99),
                                       ('data', '99')])))))
        assert_equal(len(tx.vout), 3)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   address2: 99
                                               }, {
                                                   'data': '99'
                                               }]),
        )

        self.log.info('sendrawtransaction with missing input')
        # won't exists
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1
        }]
        outputs = {self.nodes[0].getnewaddress(): 4.998}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx = pad_raw_tx(rawtx)
        rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx)

        # This will raise an exception since there are missing inputs
        assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent",
                                self.nodes[2].sendrawtransaction, rawtx['hex'])

        #####################################
        # getrawtransaction with block hash #
        #####################################

        # make a tx by sending then generate 2 blocks; block1 has the tx in it
        tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        block1, block2 = self.nodes[2].generate(2)
        self.sync_all()
        # We should be able to get the raw transaction by providing the correct
        # block
        gottx = self.nodes[0].getrawtransaction(tx, True, block1)
        assert_equal(gottx['txid'], tx)
        assert_equal(gottx['in_active_chain'], True)
        # We should not have the 'in_active_chain' flag when we don't provide a
        # block
        gottx = self.nodes[0].getrawtransaction(tx, True)
        assert_equal(gottx['txid'], tx)
        assert 'in_active_chain' not in gottx
        # We should not get the tx if we provide an unrelated block
        assert_raises_rpc_error(-5, "No such transaction found",
                                self.nodes[0].getrawtransaction, tx, True,
                                block2)
        # An invalid block hash should raise the correct errors
        assert_raises_rpc_error(-1, "JSON value is not a string as expected",
                                self.nodes[0].getrawtransaction, tx, True,
                                True)
        assert_raises_rpc_error(
            -8, "parameter 3 must be of length 64 (not 6, for 'foobar')",
            self.nodes[0].getrawtransaction, tx, True, "foobar")
        assert_raises_rpc_error(
            -8, "parameter 3 must be of length 64 (not 8, for 'abcd1234')",
            self.nodes[0].getrawtransaction, tx, True, "abcd1234")
        assert_raises_rpc_error(
            -8,
            "parameter 3 must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')",
            self.nodes[0].getrawtransaction, tx, True,
            "ZZZ0000000000000000000000000000000000000000000000000000000000000")
        assert_raises_rpc_error(
            -5, "Block hash not found", self.nodes[0].getrawtransaction, tx,
            True,
            "0000000000000000000000000000000000000000000000000000000000000000")
        # Undo the blocks and check in_active_chain
        self.nodes[0].invalidateblock(block1)
        gottx = self.nodes[0].getrawtransaction(txid=tx,
                                                verbose=True,
                                                blockhash=block1)
        assert_equal(gottx['in_active_chain'], False)
        self.nodes[0].reconsiderblock(block1)
        assert_equal(self.nodes[0].getbestblockhash(), block2)

        #
        # RAW TX MULTISIG TESTS #
        #
        # 2of2 test
        addr1 = self.nodes[2].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[2].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        # Tests for createmultisig and addmultisigaddress
        assert_raises_rpc_error(-5, "Invalid public key",
                                self.nodes[0].createmultisig, 1, ["01020304"])
        # createmultisig can only take public keys
        self.nodes[0].createmultisig(2,
                                     [addr1Obj['pubkey'], addr2Obj['pubkey']])
        # addmultisigaddress can take both pubkeys and addresses so long as
        # they are in the wallet, which is tested here.
        assert_raises_rpc_error(-5, "Invalid public key",
                                self.nodes[0].createmultisig, 2,
                                [addr1Obj['pubkey'], addr1])

        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr1])['address']

        # use balance deltas instead of absolute values
        bal = self.nodes[2].getbalance()

        # send 1.2 BCH to msig adr
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        # node2 has both keys of the 2of2 ms addr., tx should affect the
        # balance
        assert_equal(self.nodes[2].getbalance(), bal + Decimal('1.20000000'))

        # 2of3 test from different nodes
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()
        addr3 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)
        addr3Obj = self.nodes[2].getaddressinfo(addr3)

        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']
                ])['address']

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # THIS IS AN INCOMPLETE FEATURE
        # NODE2 HAS TWO OF THREE KEY AND THE FUNDS SHOULD BE SPENDABLE AND
        # COUNT AT BALANCE CALCULATION
        # for now, assume the funds of a 2of3 multisig tx are not marked as
        # spendable
        assert_equal(self.nodes[2].getbalance(), bal)

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = next(o for o in rawTx['vout']
                    if o['value'] == Decimal('2.20000000'))

        bal = self.nodes[0].getbalance()
        inputs = [{
            "txid": txId,
            "vout": vout['n'],
            "scriptPubKey": vout['scriptPubKey']['hex'],
            "amount": vout['value'],
        }]
        outputs = {self.nodes[0].getnewaddress(): 2.19}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned = self.nodes[1].signrawtransactionwithwallet(
            rawTx, inputs)
        # node1 only has one key, can't comp. sign the tx
        assert_equal(rawTxPartialSigned['complete'], False)

        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx, inputs)
        # node2 can sign the tx compl., own two of three keys
        assert_equal(rawTxSigned['complete'], True)
        self.nodes[2].sendrawtransaction(rawTxSigned['hex'])
        rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') +
                     Decimal('2.19000000'))  # block reward + tx

        rawTxBlock = self.nodes[0].getblock(self.nodes[0].getbestblockhash())

        # 2of2 test for combining transactions
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        self.nodes[1].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObjValid = self.nodes[2].getaddressinfo(mSigObj)

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # the funds of a 2of2 multisig tx should not be marked as spendable
        assert_equal(self.nodes[2].getbalance(), bal)

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = next(o for o in rawTx2['vout']
                    if o['value'] == Decimal('2.20000000'))

        bal = self.nodes[0].getbalance()
        inputs = [{
            "txid": txId,
            "vout": vout['n'],
            "scriptPubKey": vout['scriptPubKey']['hex'],
            "redeemScript": mSigObjValid['hex'],
            "amount": vout['value']
        }]
        outputs = {self.nodes[0].getnewaddress(): 2.19}
        rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned1 = self.nodes[1].signrawtransactionwithwallet(
            rawTx2, inputs)
        self.log.debug(rawTxPartialSigned1)
        # node1 only has one key, can't comp. sign the tx
        assert_equal(rawTxPartialSigned1['complete'], False)

        rawTxPartialSigned2 = self.nodes[2].signrawtransactionwithwallet(
            rawTx2, inputs)
        self.log.debug(rawTxPartialSigned2)
        # node2 only has one key, can't comp. sign the tx
        assert_equal(rawTxPartialSigned2['complete'], False)
        rawTxComb = self.nodes[2].combinerawtransaction(
            [rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']])
        self.log.debug(rawTxComb)
        self.nodes[2].sendrawtransaction(rawTxComb)
        rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') +
                     Decimal('2.19000000'))  # block reward + tx

        # getrawtransaction tests
        # 1. valid parameters - only supply txid
        txHash = rawTx["hash"]
        assert_equal(self.nodes[0].getrawtransaction(txHash),
                     rawTxSigned['hex'])

        # 2. valid parameters - supply txid and 0 for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, 0),
                     rawTxSigned['hex'])

        # 3. valid parameters - supply txid and False for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, False),
                     rawTxSigned['hex'])

        # 4. valid parameters - supply txid and 1 for verbose.
        # We only check the "hex" field of the output so we don't need to
        # update this test every time the output format changes.
        assert_equal(self.nodes[0].getrawtransaction(txHash, 1)["hex"],
                     rawTxSigned['hex'])

        # 5. valid parameters - supply txid and True for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"],
                     rawTxSigned['hex'])

        # 6. invalid parameters - supply txid and string "Flase"
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txHash,
                                "False")

        # 7. invalid parameters - supply txid and empty array
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txHash, [])

        # 8. invalid parameters - supply txid and empty dict
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txHash, {})

        # Sanity checks on verbose getrawtransaction output
        rawTxOutput = self.nodes[0].getrawtransaction(txHash, True)
        assert_equal(rawTxOutput["hex"], rawTxSigned["hex"])
        assert_equal(rawTxOutput["txid"], txHash)
        assert_equal(rawTxOutput["hash"], txHash)
        assert_greater_than(rawTxOutput["size"], 300)
        assert_equal(rawTxOutput["version"], 0x02)
        assert_equal(rawTxOutput["locktime"], 0)
        assert_equal(len(rawTxOutput["vin"]), 1)
        assert_equal(len(rawTxOutput["vout"]), 1)
        assert_equal(rawTxOutput["blockhash"], rawTxBlock["hash"])
        assert_equal(rawTxOutput["confirmations"], 3)
        assert_equal(rawTxOutput["time"], rawTxBlock["time"])
        assert_equal(rawTxOutput["blocktime"], rawTxBlock["time"])

        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'sequence': 1000
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        assert_raises_rpc_error(-8, 'Invalid parameter, missing vout key',
                                self.nodes[0].createrawtransaction, inputs,
                                outputs)

        inputs[0]['vout'] = "1"
        assert_raises_rpc_error(-8, 'Invalid parameter, vout must be a number',
                                self.nodes[0].createrawtransaction, inputs,
                                outputs)

        inputs[0]['vout'] = -1
        assert_raises_rpc_error(-8, 'Invalid parameter, vout must be positive',
                                self.nodes[0].createrawtransaction, inputs,
                                outputs)

        inputs[0]['vout'] = 1
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 1000)

        # 9. invalid parameters - sequence number out of range
        inputs[0]['sequence'] = -1
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        # 10. invalid parameters - sequence number out of range
        inputs[0]['sequence'] = 4294967296
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        inputs[0]['sequence'] = 4294967294
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 4294967294)

        ####################################
        # TRANSACTION VERSION NUMBER TESTS #
        ####################################

        # Test the minimum transaction version number that fits in a signed
        # 32-bit integer.
        tx = CTransaction()
        tx.nVersion = -0x80000000
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], -0x80000000)

        # Test the maximum transaction version number that fits in a signed
        # 32-bit integer.
        tx = CTransaction()
        tx.nVersion = 0x7fffffff
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], 0x7fffffff)

        self.log.info('sendrawtransaction/testmempoolaccept with maxfeerate')

        txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        rawTx = self.nodes[0].getrawtransaction(txId, True)
        vout = next(o for o in rawTx['vout']
                    if o['value'] == Decimal('1.00000000'))

        self.sync_all()
        inputs = [{"txid": txId, "vout": vout['n']}]
        # 1000 sat fee
        outputs = {self.nodes[0].getnewaddress(): Decimal("0.99999000")}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
        assert_equal(rawTxSigned['complete'], True)
        # 1000 sat fee, ~200 b transaction, fee rate should land around 5 sat/b = 0.00005000 BTC/kB
        # Thus, testmempoolaccept should reject
        testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']],
                                                  0.00001000)[0]
        assert_equal(testres['allowed'], False)
        assert_equal(testres['reject-reason'], '256: absurdly-high-fee')
        # and sendrawtransaction should throw
        assert_raises_rpc_error(-26, "absurdly-high-fee",
                                self.nodes[2].sendrawtransaction,
                                rawTxSigned['hex'], 0.00001000)
        # And below calls should both succeed
        testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']],
                                                  maxfeerate='0.00007000')[0]
        assert_equal(testres['allowed'], True)
        self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'],
                                         maxfeerate='0.00007000')

        ##########################################
        # Decoding weird scripts in transactions #
        ##########################################

        self.log.info('Decode correctly-formatted but weird transactions')
        tx = CTransaction()
        # empty
        self.nodes[0].decoderawtransaction(ToHex(tx))
        # truncated push
        tx.vin.append(CTxIn(COutPoint(42, 0), b'\x4e\x00\x00'))
        tx.vin.append(CTxIn(COutPoint(42, 0), b'\x4c\x10TRUNC'))
        tx.vout.append(CTxOut(0, b'\x4e\x00\x00'))
        tx.vout.append(CTxOut(0, b'\x4c\x10TRUNC'))
        self.nodes[0].decoderawtransaction(ToHex(tx))
        # giant pushes and long scripts
        tx.vin.append(CTxIn(COutPoint(42, 0),
                            CScript([b'giant push' * 10000])))
        tx.vout.append(CTxOut(0, CScript([b'giant push' * 10000])))
        self.nodes[0].decoderawtransaction(ToHex(tx))

        self.log.info('Refuse garbage after transaction')
        assert_raises_rpc_error(-22, 'TX decode failed',
                                self.nodes[0].decoderawtransaction,
                                ToHex(tx) + '00')
예제 #13
0
    def run_test(self):
        # All nodes should start with 6,250 FRAG:
        starting_balance = 6250
        for i in range(4):
            assert_equal(self.nodes[i].getbalance(), starting_balance)
            self.nodes[i].getnewaddress(
            )  # bug workaround, coins generated assigned to first getnewaddress!

        self.nodes[0].settxfee(.001)

        node0_address1 = self.nodes[0].getnewaddress()
        node0_txid1 = self.nodes[0].sendtoaddress(node0_address1, (1219 * 5))
        node0_tx1 = self.nodes[0].gettransaction(node0_txid1)

        node0_address2 = self.nodes[0].getnewaddress()
        node0_txid2 = self.nodes[0].sendtoaddress(node0_address2, (29 * 5))
        node0_tx2 = self.nodes[0].gettransaction(node0_txid2)

        assert_equal(self.nodes[0].getbalance(),
                     starting_balance + node0_tx1["fee"] + node0_tx2["fee"])

        # Coins are sent to node1_address
        node1_address = self.nodes[1].getnewaddress()

        tx1_amount = 40 * 5
        # Send tx1, and another transaction tx2 that won't be cloned
        txid1 = self.nodes[0].sendtoaddress(node1_address, tx1_amount)
        txid2 = self.nodes[0].sendtoaddress(node1_address, (20 * 5))

        # Construct a clone of tx1, to be malleated
        rawtx1 = self.nodes[0].getrawtransaction(txid1, 1)
        clone_inputs = [{
            "txid": rawtx1["vin"][0]["txid"],
            "vout": rawtx1["vin"][0]["vout"]
        }]
        clone_outputs = {
            rawtx1["vout"][0]["scriptPubKey"]["addresses"][0]:
            float(rawtx1["vout"][0]["value"]),
            rawtx1["vout"][1]["scriptPubKey"]["addresses"][0]:
            float(rawtx1["vout"][1]["value"])
        }
        clone_locktime = rawtx1["locktime"]
        clone_raw = self.nodes[0].createrawtransaction(clone_inputs,
                                                       clone_outputs,
                                                       clone_locktime)

        # createrawtransaction randomizes the order of its outputs, so swap them if necessary.
        clone_tx = CTransaction()
        clone_tx.deserialize(io.BytesIO(bytes.fromhex(clone_raw)))

        if (rawtx1["vout"][0]["value"] == tx1_amount
                and clone_tx.vout[0].nValue != tx1_amount * COIN
                or rawtx1["vout"][0]["value"] != tx1_amount
                and clone_tx.vout[0].nValue == tx1_amount * COIN):
            (clone_tx.vout[0], clone_tx.vout[1]) = (clone_tx.vout[1],
                                                    clone_tx.vout[0])

        if (rawtx1 == clone_raw):
            print("## !! Equal hex!!")
            assert (False)

        # Use a different signature hash type to sign.  This creates an equivalent but malleated clone.
        # Don't send the clone anywhere yet
        tx1_clone = self.nodes[0].signrawtransaction(
            clone_tx.serialize().hex(), None, None, "ALL|ANYONECANPAY")
        assert_equal(tx1_clone["complete"], True)

        # Have node0 mine a block, if requested:
        if (self.options.mine_block):
            self.nodes[0].generate(1)
            sync_blocks(self.nodes[0:2])

        tx1 = self.nodes[0].gettransaction(txid1)
        tx2 = self.nodes[0].gettransaction(txid2)

        # Node0's balance should be starting balance, plus 50BTC for another
        # matured block, minus tx1 and tx2 amounts, and minus transaction fees:
        expected = starting_balance + node0_tx1["fee"] + node0_tx2["fee"]
        if self.options.mine_block: expected += 250
        expected += tx1["amount"] + tx1["fee"]
        expected += tx2["amount"] + tx2["fee"]
        assert_equal(self.nodes[0].getbalance(), expected)

        if self.options.mine_block:
            assert_equal(tx1["confirmations"], 1)
            assert_equal(tx2["confirmations"], 1)
        else:
            assert_equal(tx1["confirmations"], 0)
            assert_equal(tx2["confirmations"], 0)

        # Send clone and its parent to miner
        self.nodes[2].sendrawtransaction(node0_tx1["hex"])
        txid1_clone = self.nodes[2].sendrawtransaction(tx1_clone["hex"])
        # mine a block...
        self.nodes[2].generate(1)

        # Reconnect the split network, and sync chain:
        connect_nodes(self.nodes[1], 2)
        connect_nodes(self.nodes[0], 2)
        connect_nodes(self.nodes[2], 0)
        connect_nodes(self.nodes[2], 1)

        self.nodes[2].sendrawtransaction(node0_tx2["hex"])
        self.nodes[2].sendrawtransaction(tx2["hex"])
        self.nodes[2].generate(1)  # Mine another block to make sure we sync
        sync_blocks(self.nodes)

        # Re-fetch transaction info:
        tx1 = self.nodes[0].gettransaction(txid1)
        tx1_clone = self.nodes[0].gettransaction(txid1_clone)
        tx2 = self.nodes[0].gettransaction(txid2)

        # Verify expected confirmations
        assert_equal(tx1["confirmations"], -2)
        assert_equal(tx1_clone["confirmations"], 2)
        assert_equal(tx2["confirmations"], 1)

        # Check node0's total balance; should be same as before the clone, + 100 BTC for 2 matured,
        # less possible orphaned matured subsidy
        expected += 500
        if (self.options.mine_block):
            expected -= 250
        assert_equal(self.nodes[0].getbalance(), expected)
예제 #14
0
    def _test_coin_stats_index(self):
        node = self.nodes[0]
        index_node = self.nodes[1]
        # Both none and muhash options allow the usage of the index
        index_hash_options = ['none', 'muhash']

        # Generate a normal transaction and mine it
        self.generate(node, COINBASE_MATURITY + 1)
        address = self.nodes[0].get_deterministic_priv_key().address
        node.sendtoaddress(address=address,
                           amount=10,
                           subtractfeefromamount=True)
        self.generate(node, 1)

        self.sync_blocks(timeout=120)

        self.log.info(
            "Test that gettxoutsetinfo() output is consistent with or without coinstatsindex option"
        )
        res0 = node.gettxoutsetinfo('none')

        # The fields 'disk_size' and 'transactions' do not exist on the index
        del res0['disk_size'], res0['transactions']

        for hash_option in index_hash_options:
            res1 = index_node.gettxoutsetinfo(hash_option)
            # The fields 'block_info' and 'total_unspendable_amount' only exist on the index
            del res1['block_info'], res1['total_unspendable_amount']
            res1.pop('muhash', None)

            # Everything left should be the same
            assert_equal(res1, res0)

        self.log.info(
            "Test that gettxoutsetinfo() can get fetch data on specific heights with index"
        )

        # Generate a new tip
        self.generate(node, 5)

        for hash_option in index_hash_options:
            # Fetch old stats by height
            res2 = index_node.gettxoutsetinfo(hash_option, 102)
            del res2['block_info'], res2['total_unspendable_amount']
            res2.pop('muhash', None)
            assert_equal(res0, res2)

            # Fetch old stats by hash
            res3 = index_node.gettxoutsetinfo(hash_option, res0['bestblock'])
            del res3['block_info'], res3['total_unspendable_amount']
            res3.pop('muhash', None)
            assert_equal(res0, res3)

            # It does not work without coinstatsindex
            assert_raises_rpc_error(
                -8, "Querying specific block heights requires coinstatsindex",
                node.gettxoutsetinfo, hash_option, 102)

        self.log.info("Test gettxoutsetinfo() with index and verbose flag")

        for hash_option in index_hash_options:
            # Genesis block is unspendable
            res4 = index_node.gettxoutsetinfo(hash_option, 0)
            assert_equal(res4['total_unspendable_amount'], 50)
            assert_equal(
                res4['block_info'], {
                    'unspendable': 50,
                    'prevout_spent': 0,
                    'new_outputs_ex_coinbase': 0,
                    'coinbase': 0,
                    'unspendables': {
                        'genesis_block': 50,
                        'bip30': 0,
                        'scripts': 0,
                        'unclaimed_rewards': 0
                    }
                })
            self.block_sanity_check(res4['block_info'])

            # Test an older block height that included a normal tx
            res5 = index_node.gettxoutsetinfo(hash_option, 102)
            assert_equal(res5['total_unspendable_amount'], 50)
            assert_equal(
                res5['block_info'], {
                    'unspendable': 0,
                    'prevout_spent': 50,
                    'new_outputs_ex_coinbase': Decimal('49.99995560'),
                    'coinbase': Decimal('50.00004440'),
                    'unspendables': {
                        'genesis_block': 0,
                        'bip30': 0,
                        'scripts': 0,
                        'unclaimed_rewards': 0
                    }
                })
            self.block_sanity_check(res5['block_info'])

        # Generate and send a normal tx with two outputs
        tx1_inputs = []
        tx1_outputs = {
            self.nodes[0].getnewaddress(): 21,
            self.nodes[0].getnewaddress(): 42
        }
        raw_tx1 = self.nodes[0].createrawtransaction(tx1_inputs, tx1_outputs)
        funded_tx1 = self.nodes[0].fundrawtransaction(raw_tx1)
        signed_tx1 = self.nodes[0].signrawtransactionwithwallet(
            funded_tx1['hex'])
        tx1_txid = self.nodes[0].sendrawtransaction(signed_tx1['hex'])

        # Find the right position of the 21 BTC output
        tx1_final = self.nodes[0].gettransaction(tx1_txid)
        for output in tx1_final['details']:
            if output['amount'] == Decimal(
                    '21.00000000') and output['category'] == 'receive':
                n = output['vout']

        # Generate and send another tx with an OP_RETURN output (which is unspendable)
        tx2 = CTransaction()
        tx2.vin.append(CTxIn(COutPoint(int(tx1_txid, 16), n), b''))
        tx2.vout.append(
            CTxOut(int(Decimal('20.99') * COIN),
                   CScript([OP_RETURN] + [OP_FALSE] * 30)))
        tx2_hex = self.nodes[0].signrawtransactionwithwallet(
            tx2.serialize().hex())['hex']
        self.nodes[0].sendrawtransaction(tx2_hex)

        # Include both txs in a block
        self.generate(self.nodes[0], 1)
        self.sync_all()

        for hash_option in index_hash_options:
            # Check all amounts were registered correctly
            res6 = index_node.gettxoutsetinfo(hash_option, 108)
            assert_equal(res6['total_unspendable_amount'],
                         Decimal('70.99000000'))
            assert_equal(
                res6['block_info'], {
                    'unspendable': Decimal('20.99000000'),
                    'prevout_spent': 111,
                    'new_outputs_ex_coinbase': Decimal('89.99993620'),
                    'coinbase': Decimal('50.01006380'),
                    'unspendables': {
                        'genesis_block': 0,
                        'bip30': 0,
                        'scripts': Decimal('20.99000000'),
                        'unclaimed_rewards': 0
                    }
                })
            self.block_sanity_check(res6['block_info'])

        # Create a coinbase that does not claim full subsidy and also
        # has two outputs
        cb = create_coinbase(109, nValue=35)
        cb.vout.append(CTxOut(5 * COIN, CScript([OP_FALSE])))
        cb.rehash()

        # Generate a block that includes previous coinbase
        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblock(tip)['time'] + 1
        block = create_block(int(tip, 16), cb, block_time)
        block.solve()
        self.nodes[0].submitblock(block.serialize().hex())
        self.sync_all()

        for hash_option in index_hash_options:
            res7 = index_node.gettxoutsetinfo(hash_option, 109)
            assert_equal(res7['total_unspendable_amount'],
                         Decimal('80.99000000'))
            assert_equal(
                res7['block_info'], {
                    'unspendable': 10,
                    'prevout_spent': 0,
                    'new_outputs_ex_coinbase': 0,
                    'coinbase': 40,
                    'unspendables': {
                        'genesis_block': 0,
                        'bip30': 0,
                        'scripts': 0,
                        'unclaimed_rewards': 10
                    }
                })
            self.block_sanity_check(res7['block_info'])

        self.log.info("Test that the index is robust across restarts")

        res8 = index_node.gettxoutsetinfo('muhash')
        self.restart_node(1, extra_args=self.extra_args[1])
        res9 = index_node.gettxoutsetinfo('muhash')
        assert_equal(res8, res9)

        self.generate(index_node, 1)
        res10 = index_node.gettxoutsetinfo('muhash')
        assert (res8['txouts'] < res10['txouts'])
예제 #15
0
    def create_block(self,
                     prev_hash,
                     staking_prevouts,
                     height,
                     node_n,
                     s_address,
                     fInvalid=0):
        api = self.nodes[node_n]
        # Get current time
        current_time = int(time.time())
        nTime = current_time & 0xfffffff0

        # Create coinbase TX
        coinbase = create_coinbase(height)
        coinbase.vout[0].nValue = 0
        coinbase.vout[0].scriptPubKey = b""
        coinbase.nTime = nTime
        coinbase.rehash()

        # Create Block with coinbase
        block = create_block(int(prev_hash, 16), coinbase, nTime)

        # Find valid kernel hash - Create a new private key used for block signing.
        if not block.solve_stake(staking_prevouts):
            raise Exception("Not able to solve for any prev_outpoint")

        # Create coinstake TX
        amount, prev_time, prevScript = staking_prevouts[block.prevoutStake]
        outNValue = int(amount + 250 * COIN)
        stake_tx_unsigned = CTransaction()
        stake_tx_unsigned.nTime = block.nTime
        stake_tx_unsigned.vin.append(CTxIn(block.prevoutStake))
        stake_tx_unsigned.vin[0].nSequence = 0xffffffff
        stake_tx_unsigned.vout.append(CTxOut())
        stake_tx_unsigned.vout.append(
            CTxOut(outNValue, hex_str_to_bytes(prevScript)))

        if fInvalid == 1:
            # Create a new private key and get the corresponding public key
            block_sig_key = CECKey()
            block_sig_key.set_secretbytes(hash256(pack('<I', 0xffff)))
            pubkey = block_sig_key.get_pubkey()
            stake_tx_unsigned.vout[1].scriptPubKey = CScript(
                [pubkey, OP_CHECKSIG])
        else:
            # Export the staking private key to sign the block with it
            privKey, compressed = wif_to_privkey(api.dumpprivkey(s_address))
            block_sig_key = CECKey()
            block_sig_key.set_compressed(compressed)
            block_sig_key.set_secretbytes(bytes.fromhex(privKey))
            # check the address
            addy = key_to_p2pkh(bytes_to_hex_str(block_sig_key.get_pubkey()),
                                False, True)
            assert (addy == s_address)
            if fInvalid == 2:
                # add a new output with 100 coins from the pot
                new_key = CECKey()
                new_key.set_secretbytes(hash256(pack('<I', 0xffff)))
                pubkey = new_key.get_pubkey()
                stake_tx_unsigned.vout.append(
                    CTxOut(100 * COIN, CScript([pubkey, OP_CHECKSIG])))
                stake_tx_unsigned.vout[1].nValue = outNValue - 100 * COIN

        # Sign coinstake TX and add it to the block
        stake_tx_signed_raw_hex = api.signrawtransaction(
            bytes_to_hex_str(stake_tx_unsigned.serialize()))['hex']
        stake_tx_signed = CTransaction()
        stake_tx_signed.deserialize(
            BytesIO(hex_str_to_bytes(stake_tx_signed_raw_hex)))
        block.vtx.append(stake_tx_signed)

        # Get correct MerkleRoot and rehash block
        block.hashMerkleRoot = block.calc_merkle_root()
        block.rehash()

        # sign block with block signing key and return it
        block.sign_block(block_sig_key)
        return block
예제 #16
0
    def run_test(self):
        node = self.nodes[0]

        self.log.info('Start with empty mempool and 101 blocks')
        # The last 100 coinbase transactions are premature
        blockhash = self.generate(node, 101)[0]
        txid = node.getblock(blockhash=blockhash, verbosity=2)["tx"][0]["txid"]
        assert_equal(node.getmempoolinfo()['size'], 0)

        self.log.info("Submit parent with multiple script branches to mempool")
        hashlock = hash160(b'Preimage')
        witness_script = CScript([
            OP_IF, OP_HASH160, hashlock, OP_EQUAL, OP_ELSE, OP_TRUE, OP_ENDIF
        ])
        witness_program = sha256(witness_script)
        script_pubkey = CScript([OP_0, witness_program])

        parent = CTransaction()
        parent.vin.append(CTxIn(COutPoint(int(txid, 16), 0), b""))
        parent.vout.append(CTxOut(int(9.99998 * COIN), script_pubkey))
        parent.rehash()

        privkeys = [node.get_deterministic_priv_key().key]
        raw_parent = node.signrawtransactionwithkey(
            hexstring=parent.serialize().hex(), privkeys=privkeys)['hex']
        parent_txid = node.sendrawtransaction(hexstring=raw_parent,
                                              maxfeerate=0)
        self.generate(node, 1)

        peer_wtxid_relay = node.add_p2p_connection(P2PTxInvStore())

        # Create a new transaction with witness solving first branch
        child_witness_script = CScript([OP_TRUE])
        child_witness_program = sha256(child_witness_script)
        child_script_pubkey = CScript([OP_0, child_witness_program])

        child_one = CTransaction()
        child_one.vin.append(CTxIn(COutPoint(int(parent_txid, 16), 0), b""))
        child_one.vout.append(CTxOut(int(9.99996 * COIN), child_script_pubkey))
        child_one.wit.vtxinwit.append(CTxInWitness())
        child_one.wit.vtxinwit[0].scriptWitness.stack = [
            b'Preimage', b'\x01', witness_script
        ]
        child_one_wtxid = child_one.getwtxid()
        child_one_txid = child_one.rehash()

        # Create another identical transaction with witness solving second branch
        child_two = deepcopy(child_one)
        child_two.wit.vtxinwit[0].scriptWitness.stack = [b'', witness_script]
        child_two_wtxid = child_two.getwtxid()
        child_two_txid = child_two.rehash()

        assert_equal(child_one_txid, child_two_txid)
        assert child_one_wtxid != child_two_wtxid

        self.log.info("Submit child_one to the mempool")
        txid_submitted = node.sendrawtransaction(child_one.serialize().hex())
        assert_equal(
            node.getmempoolentry(txid_submitted)['wtxid'], child_one_wtxid)

        peer_wtxid_relay.wait_for_broadcast([child_one_wtxid])
        assert_equal(node.getmempoolinfo()["unbroadcastcount"], 0)

        # testmempoolaccept reports the "already in mempool" error
        assert_equal(node.testmempoolaccept([child_one.serialize().hex()]),
                     [{
                         "txid": child_one_txid,
                         "wtxid": child_one_wtxid,
                         "allowed": False,
                         "reject-reason": "txn-already-in-mempool"
                     }])
        assert_equal(
            node.testmempoolaccept([child_two.serialize().hex()])[0], {
                "txid": child_two_txid,
                "wtxid": child_two_wtxid,
                "allowed": False,
                "reject-reason": "txn-same-nonwitness-data-in-mempool"
            })

        # sendrawtransaction will not throw but quits early when the exact same transaction is already in mempool
        node.sendrawtransaction(child_one.serialize().hex())

        self.log.info("Connect another peer that hasn't seen child_one before")
        peer_wtxid_relay_2 = node.add_p2p_connection(P2PTxInvStore())

        self.log.info("Submit child_two to the mempool")
        # sendrawtransaction will not throw but quits early when a transaction with the same non-witness data is already in mempool
        node.sendrawtransaction(child_two.serialize().hex())

        # The node should rebroadcast the transaction using the wtxid of the correct transaction
        # (child_one, which is in its mempool).
        peer_wtxid_relay_2.wait_for_broadcast([child_one_wtxid])
        assert_equal(node.getmempoolinfo()["unbroadcastcount"], 0)
예제 #17
0
    def decoderawtransaction_asm_sighashtype(self):
        """Test decoding scripts via RPC command "decoderawtransaction".

        This test is in with the "decodescript" tests because they are testing the same "asm" script decodes.
        """

        # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output
        tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal(
            '304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536',
            rpc_result['vin'][0]['scriptSig']['asm'])

        # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs.
        # it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc
        # verify that we have not altered scriptPubKey decoding.
        tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal(
            '8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0',
            rpc_result['txid'])
        assert_equal(
            '0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae',
            rpc_result['vin'][0]['scriptSig']['asm'])
        assert_equal(
            'OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG',
            rpc_result['vout'][0]['scriptPubKey']['asm'])
        assert_equal(
            'OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL',
            rpc_result['vout'][1]['scriptPubKey']['asm'])
        txSave = CTransaction()
        txSave.deserialize(BytesIO(hex_str_to_bytes(tx)))

        # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type
        tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('OP_RETURN 300602010002010001',
                     rpc_result['vout'][0]['scriptPubKey']['asm'])

        # verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks
        tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal(
            'OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG',
            rpc_result['vout'][0]['scriptPubKey']['asm'])
        assert_equal(
            'OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL',
            rpc_result['vout'][1]['scriptPubKey']['asm'])

        # verify that names shorter than 5 bytes aren't interpreted into asm as integers (issue #140)
        tx = '0071000002c323b5df3dbd501ef8e26683749fd13f785eac6d4f4c2083196a33262605e6ec010000008b48304502207cc397996cf41a4be7ce229226c2e3862557256e372dd325dfefaba26a4a44a20221008e71fc315563d04d7d92d6e2b0ef9c5e095df50777664819623156dcf3ec1c1e0141045bc24b6e33ecbe341e8195b4e8fcb3f8c7937ca6f671f799644968dc00e82d0160c5e14b687cba83840381dda04711939a225588eb0e2401d4f14dc9d3a5ccdaffffffff882be8eb700e1c6eaef2682839293ae9d5bfacf82cee80510d4dee6eed359c98000000004847304402206c6115eb47b4f3010a6c0e79ea5ee7f036fc1da22af172c4bd39a460758bb34402204cc40302837a3a61d9b1e12a99e73572f95da7b5005e5ce842a7b8b4ba90d7f901ffffffff02e007646300000000434104fb090d04c8f110012a9f4545b6cb1f93a6f22db1b35bef7e1545a4a0aef0124cd25c522851ba2120f12b124785adc6f09b13f8eaa294cfe54a601dc75f11df29ac40420f00000000005a5203662f6a394269746d65737361676520616464726573733a20424d2d3263554755687335436a6973526975514756574447334a514a47717a5967713134356d7576a9147368feca713f2a9d7780343b74007e26a4fcfcea88ac00000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal(
            'OP_NAME_UPDATE 662f6a 4269746d65737361676520616464726573733a20424d2d3263554755687335436a6973526975514756574447334a514a47717a596771313435 OP_2DROP OP_DROP OP_DUP OP_HASH160 7368feca713f2a9d7780343b74007e26a4fcfcea OP_EQUALVERIFY OP_CHECKSIG',
            rpc_result['vout'][1]['scriptPubKey']['asm'])

        # some more full transaction tests of varying specific scriptSigs. used instead of
        # tests in decodescript_script_sig because the decodescript RPC is specifically
        # for working on scriptPubKeys (argh!).
        push_signature = bytes_to_hex_str(
            txSave.vin[0].scriptSig)[2:(0x48 * 2 + 4)]
        signature = push_signature[2:]
        der_signature = signature[:-2]
        signature_sighash_decoded = der_signature + '[ALL]'
        signature_2 = der_signature + '82'
        push_signature_2 = '48' + signature_2
        signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]'

        # 1) P2PK scriptSig
        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature)
        rpc_result = self.nodes[0].decoderawtransaction(
            bytes_to_hex_str(txSave.serialize()))
        assert_equal(signature_sighash_decoded,
                     rpc_result['vin'][0]['scriptSig']['asm'])

        # make sure that the sighash decodes come out correctly for a more complex / lesser used case.
        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature_2)
        rpc_result = self.nodes[0].decoderawtransaction(
            bytes_to_hex_str(txSave.serialize()))
        assert_equal(signature_2_sighash_decoded,
                     rpc_result['vin'][0]['scriptSig']['asm'])

        # 2) multisig scriptSig
        txSave.vin[0].scriptSig = hex_str_to_bytes('00' + push_signature +
                                                   push_signature_2)
        rpc_result = self.nodes[0].decoderawtransaction(
            bytes_to_hex_str(txSave.serialize()))
        assert_equal(
            '0 ' + signature_sighash_decoded + ' ' +
            signature_2_sighash_decoded,
            rpc_result['vin'][0]['scriptSig']['asm'])

        # 3) test a scriptSig that contains more than push operations.
        # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it.
        txSave.vin[0].scriptSig = hex_str_to_bytes(
            '6a143011020701010101010101020601010101010101')
        rpc_result = self.nodes[0].decoderawtransaction(
            bytes_to_hex_str(txSave.serialize()))
        assert_equal('OP_RETURN 3011020701010101010101020601010101010101',
                     rpc_result['vin'][0]['scriptSig']['asm'])
예제 #18
0
    def run_test(self):
        self.log.info(
            'prepare some coins for multiple *rawtransaction commands')
        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[0].generate(101)
        self.sync_all()
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.5)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0)
        self.sync_all()
        self.nodes[0].generate(5)
        self.sync_all()

        self.log.info(
            'Test getrawtransaction on genesis block coinbase returns an error'
        )
        block = self.nodes[0].getblock(self.nodes[0].getblockhash(0))
        assert_raises_rpc_error(
            -5,
            "The genesis block coinbase is not considered an ordinary transaction",
            self.nodes[0].getrawtransaction, block['merkleroot'])

        self.log.info(
            'Check parameter types and required parameters of createrawtransaction'
        )
        # Test `createrawtransaction` required parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction)
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [])

        # Test `createrawtransaction` invalid extra parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [], {}, 0,
                                False, 'foo')

        # Test `createrawtransaction` invalid `inputs`
        txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'
        assert_raises_rpc_error(-3, "Expected type array",
                                self.nodes[0].createrawtransaction, 'foo', {})
        assert_raises_rpc_error(-1, "JSON value is not an object as expected",
                                self.nodes[0].createrawtransaction, ['foo'],
                                {})
        assert_raises_rpc_error(-1, "JSON value is not a string as expected",
                                self.nodes[0].createrawtransaction, [{}], {})
        assert_raises_rpc_error(
            -8, "txid must be of length 64 (not 3, for 'foo')",
            self.nodes[0].createrawtransaction, [{
                'txid': 'foo'
            }], {})
        assert_raises_rpc_error(
            -8,
            "txid must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')",
            self.nodes[0].createrawtransaction, [{
                'txid':
                'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844'
            }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid
                                }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid,
                                    'vout': 'foo'
                                }], {})
        assert_raises_rpc_error(-8,
                                "Invalid parameter, vout cannot be negative",
                                self.nodes[0].createrawtransaction, [{
                                    'txid': txid,
                                    'vout': -1
                                }], {})
        assert_raises_rpc_error(
            -8, "Invalid parameter, sequence number is out of range",
            self.nodes[0].createrawtransaction, [{
                'txid': txid,
                'vout': 0,
                'sequence': -1
            }], {})

        # Test `createrawtransaction` invalid `outputs`
        address = self.nodes[0].getnewaddress()
        address2 = self.nodes[0].getnewaddress()
        assert_raises_rpc_error(-1, "JSON value is not an array as expected",
                                self.nodes[0].createrawtransaction, [], 'foo')
        self.nodes[0].createrawtransaction(
            inputs=[],
            outputs={})  # Should not throw for backwards compatibility
        self.nodes[0].createrawtransaction(inputs=[], outputs=[])
        assert_raises_rpc_error(-8, "Data must be hexadecimal string",
                                self.nodes[0].createrawtransaction, [],
                                {'data': 'foo'})
        assert_raises_rpc_error(-5, "Invalid address",
                                self.nodes[0].createrawtransaction, [],
                                {'foo': 0})
        assert_raises_rpc_error(-3, "Invalid amount",
                                self.nodes[0].createrawtransaction, [],
                                {address: 'foo'})
        assert_raises_rpc_error(-3, "Amount out of range",
                                self.nodes[0].createrawtransaction, [],
                                {address: -1})
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: %s" % address,
            self.nodes[0].createrawtransaction, [],
            multidict([(address, 1), (address, 1)]))
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: %s" % address,
            self.nodes[0].createrawtransaction, [], [{
                address: 1
            }, {
                address: 1
            }])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
                                self.nodes[0].createrawtransaction, [],
                                [{
                                    "data": 'aa'
                                }, {
                                    "data": "bb"
                                }])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
                                self.nodes[0].createrawtransaction, [],
                                multidict([("data", 'aa'), ("data", "bb")]))
        assert_raises_rpc_error(
            -8,
            "Invalid parameter, key-value pair must contain exactly one key",
            self.nodes[0].createrawtransaction, [], [{
                'a': 1,
                'b': 2
            }])
        assert_raises_rpc_error(
            -8, "Invalid parameter, key-value pair not an object as expected",
            self.nodes[0].createrawtransaction, [],
            [['key-value pair1'], ['2']])

        # Test `createrawtransaction` invalid `locktime`
        assert_raises_rpc_error(-3, "Expected type number",
                                self.nodes[0].createrawtransaction, [], {},
                                'foo')
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {}, -1)
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {},
                                4294967296)

        # Test `createrawtransaction` invalid `replaceable`
        assert_raises_rpc_error(-3, "Expected type bool",
                                self.nodes[0].createrawtransaction, [], {}, 0,
                                'foo')

        self.log.info(
            'Check that createrawtransaction accepts an array and object as outputs'
        )
        tx = CTransaction()
        # One output
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }], outputs={address: 99}))))
        assert_equal(len(tx.vout), 1)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }]),
        )
        # Two outputs
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }],
                    outputs=OrderedDict([(address, 99), (address2, 99)])))))
        assert_equal(len(tx.vout), 2)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   address2: 99
                                               }]),
        )
        # Multiple mixed outputs
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }],
                    outputs=multidict([(address, 99), (address2, 99),
                                       ('data', '99')])))))
        assert_equal(len(tx.vout), 3)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   address2: 99
                                               }, {
                                                   'data': '99'
                                               }]),
        )

        for type in ["bech32", "p2sh-segwit", "legacy"]:
            addr = self.nodes[0].getnewaddress("", type)
            addrinfo = self.nodes[0].getaddressinfo(addr)
            pubkey = addrinfo["scriptPubKey"]

            self.log.info('sendrawtransaction with missing prevtx info (%s)' %
                          (type))

            # Test `signrawtransactionwithwallet` invalid `prevtxs`
            inputs = [{'txid': txid, 'vout': 3, 'sequence': 1000}]
            outputs = {self.nodes[0].getnewaddress(): 1}
            rawtx = self.nodes[0].createrawtransaction(inputs, outputs)

            prevtx = dict(txid=txid, scriptPubKey=pubkey, vout=3, amount=1)
            succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx])
            assert succ["complete"]
            if type == "legacy":
                del prevtx["amount"]
                succ = self.nodes[0].signrawtransactionwithwallet(
                    rawtx, [prevtx])
                assert succ["complete"]

            if type != "legacy":
                assert_raises_rpc_error(
                    -3, "Missing amount",
                    self.nodes[0].signrawtransactionwithwallet, rawtx,
                    [{
                        "txid": txid,
                        "scriptPubKey": pubkey,
                        "vout": 3,
                    }])

            assert_raises_rpc_error(-3, "Missing vout",
                                    self.nodes[0].signrawtransactionwithwallet,
                                    rawtx, [{
                                        "txid": txid,
                                        "scriptPubKey": pubkey,
                                        "amount": 1,
                                    }])
            assert_raises_rpc_error(-3, "Missing txid",
                                    self.nodes[0].signrawtransactionwithwallet,
                                    rawtx, [{
                                        "scriptPubKey": pubkey,
                                        "vout": 3,
                                        "amount": 1,
                                    }])
            assert_raises_rpc_error(-3, "Missing scriptPubKey",
                                    self.nodes[0].signrawtransactionwithwallet,
                                    rawtx, [{
                                        "txid": txid,
                                        "vout": 3,
                                        "amount": 1
                                    }])

        #########################################
        # sendrawtransaction with missing input #
        #########################################

        self.log.info('sendrawtransaction with missing input')
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1
        }]  #won't exists
        outputs = {self.nodes[0].getnewaddress(): 4.998}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx)

        # This will raise an exception since there are missing inputs
        assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent",
                                self.nodes[2].sendrawtransaction, rawtx['hex'])

        #####################################
        # getrawtransaction with block hash #
        #####################################

        # make a tx by sending then generate 2 blocks; block1 has the tx in it
        tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        block1, block2 = self.nodes[2].generate(2)
        self.sync_all()
        # We should be able to get the raw transaction by providing the correct block
        gottx = self.nodes[0].getrawtransaction(tx, True, block1)
        assert_equal(gottx['txid'], tx)
        assert_equal(gottx['in_active_chain'], True)
        # We should not have the 'in_active_chain' flag when we don't provide a block
        gottx = self.nodes[0].getrawtransaction(tx, True)
        assert_equal(gottx['txid'], tx)
        assert 'in_active_chain' not in gottx
        # We should not get the tx if we provide an unrelated block
        assert_raises_rpc_error(-5, "No such transaction found",
                                self.nodes[0].getrawtransaction, tx, True,
                                block2)
        # An invalid block hash should raise the correct errors
        assert_raises_rpc_error(-1, "JSON value is not a string as expected",
                                self.nodes[0].getrawtransaction, tx, True,
                                True)
        assert_raises_rpc_error(
            -8, "parameter 3 must be of length 64 (not 6, for 'foobar')",
            self.nodes[0].getrawtransaction, tx, True, "foobar")
        assert_raises_rpc_error(
            -8, "parameter 3 must be of length 64 (not 8, for 'abcd1234')",
            self.nodes[0].getrawtransaction, tx, True, "abcd1234")
        assert_raises_rpc_error(
            -8,
            "parameter 3 must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')",
            self.nodes[0].getrawtransaction, tx, True,
            "ZZZ0000000000000000000000000000000000000000000000000000000000000")
        assert_raises_rpc_error(
            -5, "Block hash not found", self.nodes[0].getrawtransaction, tx,
            True,
            "0000000000000000000000000000000000000000000000000000000000000000")
        # Undo the blocks and check in_active_chain
        self.nodes[0].invalidateblock(block1)
        gottx = self.nodes[0].getrawtransaction(txid=tx,
                                                verbose=True,
                                                blockhash=block1)
        assert_equal(gottx['in_active_chain'], False)
        self.nodes[0].reconsiderblock(block1)
        assert_equal(self.nodes[0].getbestblockhash(), block2)

        #########################
        # RAW TX MULTISIG TESTS #
        #########################
        # 2of2 test
        addr1 = self.nodes[2].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[2].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        # Tests for createmultisig and addmultisigaddress
        assert_raises_rpc_error(-5, "Invalid public key",
                                self.nodes[0].createmultisig, 1, ["01020304"])
        self.nodes[0].createmultisig(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']
                ])  # createmultisig can only take public keys
        assert_raises_rpc_error(
            -5, "Invalid public key", self.nodes[0].createmultisig, 2,
            [addr1Obj['pubkey'], addr1]
        )  # addmultisigaddress can take both pubkeys and addresses so long as they are in the wallet, which is tested here.

        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr1])['address']

        #use balance deltas instead of absolute values
        bal = self.nodes[2].getbalance()

        # send 1.2 BTC to msig adr
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(
            self.nodes[2].getbalance(), bal + Decimal('1.20000000')
        )  #node2 has both keys of the 2of2 ms addr., tx should affect the balance

        # 2of3 test from different nodes
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()
        addr3 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)
        addr3Obj = self.nodes[2].getaddressinfo(addr3)

        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']
                ])['address']

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        #THIS IS AN INCOMPLETE FEATURE
        #NODE2 HAS TWO OF THREE KEY AND THE FUNDS SHOULD BE SPENDABLE AND COUNT AT BALANCE CALCULATION
        assert_equal(
            self.nodes[2].getbalance(), bal
        )  #for now, assume the funds of a 2of3 multisig tx are not marked as spendable

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = next(o for o in rawTx['vout']
                    if o['value'] == Decimal('2.20000000'))

        bal = self.nodes[0].getbalance()
        inputs = [{
            "txid": txId,
            "vout": vout['n'],
            "scriptPubKey": vout['scriptPubKey']['hex'],
            "amount": vout['value']
        }]
        outputs = {self.nodes[0].getnewaddress(): 2.19}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned = self.nodes[1].signrawtransactionwithwallet(
            rawTx, inputs)
        assert_equal(rawTxPartialSigned['complete'],
                     False)  #node1 only has one key, can't comp. sign the tx

        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx, inputs)
        assert_equal(
            rawTxSigned['complete'],
            True)  #node2 can sign the tx compl., own two of three keys
        self.nodes[2].sendrawtransaction(rawTxSigned['hex'])
        rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') +
                     Decimal('2.19000000'))  #block reward + tx

        # 2of2 test for combining transactions
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        self.nodes[1].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObjValid = self.nodes[2].getaddressinfo(mSigObj)

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        assert_equal(
            self.nodes[2].getbalance(), bal
        )  # the funds of a 2of2 multisig tx should not be marked as spendable

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = next(o for o in rawTx2['vout']
                    if o['value'] == Decimal('2.20000000'))

        bal = self.nodes[0].getbalance()
        inputs = [{
            "txid": txId,
            "vout": vout['n'],
            "scriptPubKey": vout['scriptPubKey']['hex'],
            "redeemScript": mSigObjValid['hex'],
            "amount": vout['value']
        }]
        outputs = {self.nodes[0].getnewaddress(): 2.19}
        rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned1 = self.nodes[1].signrawtransactionwithwallet(
            rawTx2, inputs)
        self.log.debug(rawTxPartialSigned1)
        assert_equal(rawTxPartialSigned1['complete'],
                     False)  #node1 only has one key, can't comp. sign the tx

        rawTxPartialSigned2 = self.nodes[2].signrawtransactionwithwallet(
            rawTx2, inputs)
        self.log.debug(rawTxPartialSigned2)
        assert_equal(rawTxPartialSigned2['complete'],
                     False)  #node2 only has one key, can't comp. sign the tx
        rawTxComb = self.nodes[2].combinerawtransaction(
            [rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']])
        self.log.debug(rawTxComb)
        self.nodes[2].sendrawtransaction(rawTxComb)
        rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') +
                     Decimal('2.19000000'))  #block reward + tx

        # decoderawtransaction tests
        # witness transaction
        encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000"
        decrawtx = self.nodes[0].decoderawtransaction(
            encrawtx, True)  # decode as witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
        assert_raises_rpc_error(
            -22, 'TX decode failed', self.nodes[0].decoderawtransaction,
            encrawtx, False)  # force decode as non-witness transaction
        # non-witness transaction
        encrawtx = "01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000"
        decrawtx = self.nodes[0].decoderawtransaction(
            encrawtx, False)  # decode as non-witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))

        # getrawtransaction tests
        # 1. valid parameters - only supply txid
        txId = rawTx["txid"]
        assert_equal(self.nodes[0].getrawtransaction(txId), rawTxSigned['hex'])

        # 2. valid parameters - supply txid and 0 for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txId, 0),
                     rawTxSigned['hex'])

        # 3. valid parameters - supply txid and False for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txId, False),
                     rawTxSigned['hex'])

        # 4. valid parameters - supply txid and 1 for verbose.
        # We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
        assert_equal(self.nodes[0].getrawtransaction(txId, 1)["hex"],
                     rawTxSigned['hex'])

        # 5. valid parameters - supply txid and True for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txId, True)["hex"],
                     rawTxSigned['hex'])

        # 6. invalid parameters - supply txid and string "Flase"
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txId, "Flase")

        # 7. invalid parameters - supply txid and empty array
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txId, [])

        # 8. invalid parameters - supply txid and empty dict
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txId, {})

        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 1000
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 1000)

        # 9. invalid parameters - sequence number out of range
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': -1
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        # 10. invalid parameters - sequence number out of range
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 4294967296
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 4294967294
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 4294967294)

        ####################################
        # TRANSACTION VERSION NUMBER TESTS #
        ####################################

        # Test the minimum transaction version number that fits in a signed 32-bit integer.
        # As transaction version is unsigned, this should convert to its unsigned equivalent.
        tx = CTransaction()
        tx.nVersion = -0x80000000
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], 0x80000000)

        # Test the maximum transaction version number that fits in a signed 32-bit integer.
        tx = CTransaction()
        tx.nVersion = 0x7fffffff
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], 0x7fffffff)

        self.log.info('sendrawtransaction/testmempoolaccept with maxfeerate')

        # Test a transaction with a small fee.
        txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        rawTx = self.nodes[0].getrawtransaction(txId, True)
        vout = next(o for o in rawTx['vout']
                    if o['value'] == Decimal('1.00000000'))

        self.sync_all()
        inputs = [{"txid": txId, "vout": vout['n']}]
        # Fee 10,000 satoshis, (1 - (10000 sat * 0.00000001 BTC/sat)) = 0.9999
        outputs = {self.nodes[0].getnewaddress(): Decimal("0.99990000")}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
        assert_equal(rawTxSigned['complete'], True)
        # Fee 10,000 satoshis, ~100 b transaction, fee rate should land around 100 sat/byte = 0.00100000 BTC/kB
        # Thus, testmempoolaccept should reject
        testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']],
                                                  0.00001000)[0]
        assert_equal(testres['allowed'], False)
        assert_equal(testres['reject-reason'], 'max-fee-exceeded')
        # and sendrawtransaction should throw
        assert_raises_rpc_error(
            -25,
            'Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)',
            self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
        # and the following calls should both succeed
        testres = self.nodes[2].testmempoolaccept(
            rawtxs=[rawTxSigned['hex']])[0]
        assert_equal(testres['allowed'], True)
        self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'])

        # Test a transaction with a large fee.
        txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        rawTx = self.nodes[0].getrawtransaction(txId, True)
        vout = next(o for o in rawTx['vout']
                    if o['value'] == Decimal('1.00000000'))

        self.sync_all()
        inputs = [{"txid": txId, "vout": vout['n']}]
        # Fee 2,000,000 satoshis, (1 - (2000000 sat * 0.00000001 BTC/sat)) = 0.98
        outputs = {self.nodes[0].getnewaddress(): Decimal("0.98000000")}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
        assert_equal(rawTxSigned['complete'], True)
        # Fee 2,000,000 satoshis, ~100 b transaction, fee rate should land around 20,000 sat/byte = 0.20000000 BTC/kB
        # Thus, testmempoolaccept should reject
        testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
        assert_equal(testres['allowed'], False)
        assert_equal(testres['reject-reason'], 'max-fee-exceeded')
        # and sendrawtransaction should throw
        assert_raises_rpc_error(
            -25,
            'Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)',
            self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
        # and the following calls should both succeed
        testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']],
                                                  maxfeerate='0.20000000')[0]
        assert_equal(testres['allowed'], True)
        self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'],
                                         maxfeerate='0.20000000')
예제 #19
0
    def test_rbf(self):
        node = self.nodes[0]
        coin = self.coins.pop()
        inputs = [{
            "txid": coin["txid"],
            "vout": 0,
            "sequence": BIP125_SEQUENCE_NUMBER
        }]
        fee = Decimal('0.00125000')
        output = {node.get_deterministic_priv_key().address: 50 - fee}
        raw_replaceable_tx = node.createrawtransaction(inputs, output)
        signed_replaceable_tx = node.signrawtransactionwithkey(
            hexstring=raw_replaceable_tx, privkeys=self.privkeys)
        testres_replaceable = node.testmempoolaccept(
            [signed_replaceable_tx["hex"]])
        replaceable_tx = CTransaction()
        replaceable_tx.deserialize(
            BytesIO(hex_str_to_bytes(signed_replaceable_tx["hex"])))
        assert_equal(testres_replaceable, [{
            "txid": replaceable_tx.rehash(),
            "wtxid": replaceable_tx.getwtxid(),
            "allowed": True,
            "vsize": replaceable_tx.get_vsize(),
            "fees": {
                "base": fee
            }
        }])

        # Replacement transaction is identical except has double the fee
        replacement_tx = CTransaction()
        replacement_tx.deserialize(
            BytesIO(hex_str_to_bytes(signed_replaceable_tx["hex"])))
        replacement_tx.vout[0].nValue -= int(fee * COIN)  # Doubled fee
        signed_replacement_tx = node.signrawtransactionwithkey(
            replacement_tx.serialize().hex(), self.privkeys)
        replacement_tx.deserialize(
            BytesIO(hex_str_to_bytes(signed_replacement_tx["hex"])))

        self.log.info(
            "Test that transactions within a package cannot replace each other"
        )
        testres_rbf_conflicting = node.testmempoolaccept(
            [signed_replaceable_tx["hex"], signed_replacement_tx["hex"]])
        assert_equal(testres_rbf_conflicting,
                     [{
                         "txid": replaceable_tx.rehash(),
                         "wtxid": replaceable_tx.getwtxid(),
                         "package-error": "conflict-in-package"
                     }, {
                         "txid": replacement_tx.rehash(),
                         "wtxid": replacement_tx.getwtxid(),
                         "package-error": "conflict-in-package"
                     }])

        self.log.info(
            "Test that packages cannot conflict with mempool transactions, even if a valid BIP125 RBF"
        )
        node.sendrawtransaction(signed_replaceable_tx["hex"])
        testres_rbf_single = node.testmempoolaccept(
            [signed_replacement_tx["hex"]])
        # This transaction is a valid BIP125 replace-by-fee
        assert testres_rbf_single[0]["allowed"]
        testres_rbf_package = self.independent_txns_testres_blank + [
            {
                "txid": replacement_tx.rehash(),
                "wtxid": replacement_tx.getwtxid(),
                "allowed": False,
                "reject-reason": "bip125-replacement-disallowed"
            }
        ]
        self.assert_testres_equal(
            self.independent_txns_hex + [signed_replacement_tx["hex"]],
            testres_rbf_package)
예제 #20
0
    def run_test(self):
        self.log.info(
            'prepare some coins for multiple *rawtransaction commands')
        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[0].generate(101)
        self.sync_all()
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.5)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0)
        self.sync_all()
        self.nodes[0].generate(5)
        self.sync_all()

        self.log.info(
            'Test getrawtransaction on genesis block coinbase returns an error'
        )
        block = self.nodes[0].getblock(self.nodes[0].getblockhash(0))
        assert_raises_rpc_error(
            -5,
            "The genesis block coinbase is not considered an ordinary transaction",
            self.nodes[0].getrawtransaction, block['merkleroot'])

        self.log.info(
            'Check parameter types and required parameters of createrawtransaction'
        )
        # Test `createrawtransaction` required parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction)
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [])

        # Test `createrawtransaction` invalid extra parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [], {}, 0,
                                False, 'foo')

        # Test `createrawtransaction` invalid `inputs`
        txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'
        assert_raises_rpc_error(-3, "Expected type array",
                                self.nodes[0].createrawtransaction, 'foo', {})
        assert_raises_rpc_error(-1, "JSON value is not an object as expected",
                                self.nodes[0].createrawtransaction, ['foo'],
                                {})
        assert_raises_rpc_error(-8, "txid must be hexadecimal string",
                                self.nodes[0].createrawtransaction, [{}], {})
        assert_raises_rpc_error(-8, "txid must be hexadecimal string",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': 'foo'
                                }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid
                                }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid,
                                    'vout': 'foo'
                                }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, vout must be positive",
                                self.nodes[0].createrawtransaction, [{
                                    'txid': txid,
                                    'vout': -1
                                }], {})
        assert_raises_rpc_error(
            -8, "Invalid parameter, sequence number is out of range",
            self.nodes[0].createrawtransaction, [{
                'txid': txid,
                'vout': 0,
                'sequence': -1
            }], {})

        # Test `createrawtransaction` invalid `outputs`
        address = self.nodes[0].getnewaddress()
        address2 = self.nodes[0].getnewaddress()
        assert_raises_rpc_error(-1, "JSON value is not an array as expected",
                                self.nodes[0].createrawtransaction, [], 'foo')
        self.nodes[0].createrawtransaction(
            inputs=[],
            outputs={})  # Should not throw for backwards compatibility
        self.nodes[0].createrawtransaction(inputs=[], outputs=[])
        assert_raises_rpc_error(-8, "Data must be hexadecimal string",
                                self.nodes[0].createrawtransaction, [],
                                {'data': 'foo'})
        assert_raises_rpc_error(-5, "Invalid Bitcoin address",
                                self.nodes[0].createrawtransaction, [],
                                {'foo': 0})
        assert_raises_rpc_error(-3, "Invalid amount",
                                self.nodes[0].createrawtransaction, [],
                                {address: 'foo'})
        assert_raises_rpc_error(-3, "Amount out of range",
                                self.nodes[0].createrawtransaction, [],
                                {address: -1})
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: %s" % address,
            self.nodes[0].createrawtransaction, [],
            multidict([(address, 1), (address, 1)]))
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: %s" % address,
            self.nodes[0].createrawtransaction, [], [{
                address: 1
            }, {
                address: 1
            }])
        assert_raises_rpc_error(
            -8,
            "Invalid parameter, key-value pair must contain exactly one key",
            self.nodes[0].createrawtransaction, [], [{
                'a': 1,
                'b': 2
            }])
        assert_raises_rpc_error(
            -8, "Invalid parameter, key-value pair not an object as expected",
            self.nodes[0].createrawtransaction, [],
            [['key-value pair1'], ['2']])

        # Test `createrawtransaction` invalid `locktime`
        assert_raises_rpc_error(-3, "Expected type number",
                                self.nodes[0].createrawtransaction, [], {},
                                'foo')
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {}, -1)
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {},
                                4294967296)

        # Test `createrawtransaction` invalid `replaceable`
        assert_raises_rpc_error(-3, "Expected type bool",
                                self.nodes[0].createrawtransaction, [], {}, 0,
                                'foo')

        self.log.info(
            'Check that createrawtransaction accepts an array and object as outputs'
        )
        tx = CTransaction()
        # One output
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }], outputs={address: 99}))))
        assert_equal(len(tx.vout), 1)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }]),
        )
        # Two outputs
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }],
                    outputs=OrderedDict([(address, 99), (address2, 99)])))))
        assert_equal(len(tx.vout), 2)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   address2: 99
                                               }]),
        )
        # Two data outputs
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }],
                    outputs=multidict([('data', '99'), ('data', '99')])))))
        assert_equal(len(tx.vout), 2)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   'data': '99'
                                               }, {
                                                   'data': '99'
                                               }]),
        )
        # Multiple mixed outputs
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }],
                    outputs=multidict([(address, 99), ('data', '99'),
                                       ('data', '99')])))))
        assert_equal(len(tx.vout), 3)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   'data': '99'
                                               }, {
                                                   'data': '99'
                                               }]),
        )

        self.log.info('sendrawtransaction with missing input')
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1
        }]  #won't exists
        outputs = {self.nodes[0].getnewaddress(): 4.998}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx)

        # This will raise an exception since there are missing inputs
        assert_raises_rpc_error(-25, "Missing inputs",
                                self.nodes[2].sendrawtransaction, rawtx['hex'])

        #####################################
        # getrawtransaction with block hash #
        #####################################

        # make a tx by sending then generate 2 blocks; block1 has the tx in it
        tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        block1, block2 = self.nodes[2].generate(2)
        self.sync_all()
        # We should be able to get the raw transaction by providing the correct block
        gottx = self.nodes[0].getrawtransaction(tx, True, block1)
        assert_equal(gottx['txid'], tx)
        assert_equal(gottx['in_active_chain'], True)
        # We should not have the 'in_active_chain' flag when we don't provide a block
        gottx = self.nodes[0].getrawtransaction(tx, True)
        assert_equal(gottx['txid'], tx)
        assert 'in_active_chain' not in gottx
        # We should not get the tx if we provide an unrelated block
        assert_raises_rpc_error(-5, "No such transaction found",
                                self.nodes[0].getrawtransaction, tx, True,
                                block2)
        # An invalid block hash should raise the correct errors
        assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal",
                                self.nodes[0].getrawtransaction, tx, True,
                                True)
        assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal",
                                self.nodes[0].getrawtransaction, tx, True,
                                "foobar")
        assert_raises_rpc_error(-8, "parameter 3 must be of length 64",
                                self.nodes[0].getrawtransaction, tx, True,
                                "abcd1234")
        assert_raises_rpc_error(
            -5, "Block hash not found", self.nodes[0].getrawtransaction, tx,
            True,
            "0000000000000000000000000000000000000000000000000000000000000000")
        # Undo the blocks and check in_active_chain
        self.nodes[0].invalidateblock(block1)
        gottx = self.nodes[0].getrawtransaction(txid=tx,
                                                verbose=True,
                                                blockhash=block1)
        assert_equal(gottx['in_active_chain'], False)
        self.nodes[0].reconsiderblock(block1)
        assert_equal(self.nodes[0].getbestblockhash(), block2)

        #########################
        # RAW TX MULTISIG TESTS #
        #########################
        # 2of2 test
        addr1 = self.nodes[2].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[2].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        # Tests for createmultisig and addmultisigaddress
        assert_raises_rpc_error(-5, "Invalid public key",
                                self.nodes[0].createmultisig, 1, ["01020304"])
        self.nodes[0].createmultisig(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']
                ])  # createmultisig can only take public keys
        assert_raises_rpc_error(
            -5, "Invalid public key", self.nodes[0].createmultisig, 2,
            [addr1Obj['pubkey'], addr1]
        )  # addmultisigaddress can take both pubkeys and addresses so long as they are in the wallet, which is tested here.

        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr1])['address']

        #use balance deltas instead of absolute values
        bal = self.nodes[2].getbalance()

        # send 1.2 PTC to msig adr
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(
            self.nodes[2].getbalance(), bal + Decimal('1.20000000')
        )  #node2 has both keys of the 2of2 ms addr., tx should affect the balance

        # 2of3 test from different nodes
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()
        addr3 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)
        addr3Obj = self.nodes[2].getaddressinfo(addr3)

        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']
                ])['address']

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        #THIS IS AN INCOMPLETE FEATURE
        #NODE2 HAS TWO OF THREE KEY AND THE FUNDS SHOULD BE SPENDABLE AND COUNT AT BALANCE CALCULATION
        assert_equal(
            self.nodes[2].getbalance(), bal
        )  #for now, assume the funds of a 2of3 multisig tx are not marked as spendable

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = False
        for outpoint in rawTx['vout']:
            if outpoint['value'] == Decimal('2.20000000'):
                vout = outpoint
                break

        bal = self.nodes[0].getbalance()
        inputs = [{
            "txid": txId,
            "vout": vout['n'],
            "scriptPubKey": vout['scriptPubKey']['hex'],
            "amount": vout['value']
        }]
        outputs = {self.nodes[0].getnewaddress(): 2.19}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned = self.nodes[1].signrawtransactionwithwallet(
            rawTx, inputs)
        assert_equal(rawTxPartialSigned['complete'],
                     False)  #node1 only has one key, can't comp. sign the tx

        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx, inputs)
        assert_equal(
            rawTxSigned['complete'],
            True)  #node2 can sign the tx compl., own two of three keys
        self.nodes[2].sendrawtransaction(rawTxSigned['hex'])
        rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') +
                     Decimal('2.19000000'))  #block reward + tx

        # 2of2 test for combining transactions
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        self.nodes[1].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObjValid = self.nodes[2].getaddressinfo(mSigObj)

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        assert_equal(
            self.nodes[2].getbalance(), bal
        )  # the funds of a 2of2 multisig tx should not be marked as spendable

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = False
        for outpoint in rawTx2['vout']:
            if outpoint['value'] == Decimal('2.20000000'):
                vout = outpoint
                break

        bal = self.nodes[0].getbalance()
        inputs = [{
            "txid": txId,
            "vout": vout['n'],
            "scriptPubKey": vout['scriptPubKey']['hex'],
            "redeemScript": mSigObjValid['hex'],
            "amount": vout['value']
        }]
        outputs = {self.nodes[0].getnewaddress(): 2.19}
        rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned1 = self.nodes[1].signrawtransactionwithwallet(
            rawTx2, inputs)
        self.log.debug(rawTxPartialSigned1)
        assert_equal(rawTxPartialSigned1['complete'],
                     False)  #node1 only has one key, can't comp. sign the tx

        rawTxPartialSigned2 = self.nodes[2].signrawtransactionwithwallet(
            rawTx2, inputs)
        self.log.debug(rawTxPartialSigned2)
        assert_equal(rawTxPartialSigned2['complete'],
                     False)  #node2 only has one key, can't comp. sign the tx
        rawTxComb = self.nodes[2].combinerawtransaction(
            [rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']])
        self.log.debug(rawTxComb)
        self.nodes[2].sendrawtransaction(rawTxComb)
        rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') +
                     Decimal('2.19000000'))  #block reward + tx

        # decoderawtransaction tests
        # witness transaction
        encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000000000000"
        decrawtx = self.nodes[0].decoderawtransaction(
            encrawtx, True)  # decode as witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
        assert_raises_rpc_error(
            -22, 'TX decode failed', self.nodes[0].decoderawtransaction,
            encrawtx, False)  # force decode as non-witness transaction
        # non-witness transaction
        encrawtx = "01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000"
        decrawtx = self.nodes[0].decoderawtransaction(
            encrawtx, False)  # decode as non-witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))

        # getrawtransaction tests
        # 1. valid parameters - only supply txid
        txHash = rawTx["hash"]
        assert_equal(self.nodes[0].getrawtransaction(txHash),
                     rawTxSigned['hex'])

        # 2. valid parameters - supply txid and 0 for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, 0),
                     rawTxSigned['hex'])

        # 3. valid parameters - supply txid and False for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, False),
                     rawTxSigned['hex'])

        # 4. valid parameters - supply txid and 1 for verbose.
        # We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
        assert_equal(self.nodes[0].getrawtransaction(txHash, 1)["hex"],
                     rawTxSigned['hex'])

        # 5. valid parameters - supply txid and True for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"],
                     rawTxSigned['hex'])

        # 6. invalid parameters - supply txid and string "Flase"
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txHash,
                                "Flase")

        # 7. invalid parameters - supply txid and empty array
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txHash, [])

        # 8. invalid parameters - supply txid and empty dict
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txHash, {})

        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 1000
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 1000)

        # 9. invalid parameters - sequence number out of range
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': -1
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        # 10. invalid parameters - sequence number out of range
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 4294967296
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 4294967294
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 4294967294)

        ####################################
        # TRANSACTION VERSION NUMBER TESTS #
        ####################################

        # Test the minimum transaction version number that fits in a signed 32-bit integer.
        tx = CTransaction()
        tx.nVersion = -0x80000000
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], -0x80000000)

        # Test the maximum transaction version number that fits in a signed 32-bit integer.
        tx = CTransaction()
        tx.nVersion = 0x7fffffff
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], 0x7fffffff)
예제 #21
0
    def test_sequence_lock_confirmed_inputs(self):
        # Create lots of confirmed utxos, and use them to generate lots of random
        # transactions.
        max_outputs = 50
        addresses = []
        while len(addresses) < max_outputs:
            addresses.append(self.nodes[0].getnewaddress())
        while len(self.nodes[0].listunspent()) < 200:
            import random
            random.shuffle(addresses)
            num_outputs = random.randint(1, max_outputs)
            outputs = {}
            for i in range(num_outputs):
                outputs[addresses[i]] = random.randint(1, 20) * 0.01
            self.nodes[0].sendmany("", outputs)
            self.generate(self.nodes[0], 1)

        utxos = self.nodes[0].listunspent()

        # Try creating a lot of random transactions.
        # Each time, choose a random number of inputs, and randomly set
        # some of those inputs to be sequence locked (and randomly choose
        # between height/time locking). Small random chance of making the locks
        # all pass.
        for _ in range(400):
            # Randomly choose up to 10 inputs
            num_inputs = random.randint(1, 10)
            random.shuffle(utxos)

            # Track whether any sequence locks used should fail
            should_pass = True

            # Track whether this transaction was built with sequence locks
            using_sequence_locks = False

            tx = CTransaction()
            tx.nVersion = 2
            value = 0
            for j in range(num_inputs):
                sequence_value = 0xfffffffe  # this disables sequence locks

                # 50% chance we enable sequence locks
                if random.randint(0, 1):
                    using_sequence_locks = True

                    # 10% of the time, make the input sequence value pass
                    input_will_pass = (random.randint(1, 10) == 1)
                    sequence_value = utxos[j]["confirmations"]
                    if not input_will_pass:
                        sequence_value += 1
                        should_pass = False

                    # Figure out what the median-time-past was for the confirmed input
                    # Note that if an input has N confirmations, we're going back N blocks
                    # from the tip so that we're looking up MTP of the block
                    # PRIOR to the one the input appears in, as per the BIP68 spec.
                    orig_time = self.get_median_time_past(
                        utxos[j]["confirmations"])
                    cur_time = self.get_median_time_past(0)  # MTP of the tip

                    # can only timelock this input if it's not too old -- otherwise use height
                    can_time_lock = True
                    if ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY
                        ) >= SEQUENCE_LOCKTIME_MASK:
                        can_time_lock = False

                    # if time-lockable, then 50% chance we make this a time lock
                    if random.randint(0, 1) and can_time_lock:
                        # Find first time-lock value that fails, or latest one that succeeds
                        time_delta = sequence_value << SEQUENCE_LOCKTIME_GRANULARITY
                        if input_will_pass and time_delta > cur_time - orig_time:
                            sequence_value = ((cur_time - orig_time) >>
                                              SEQUENCE_LOCKTIME_GRANULARITY)
                        elif (not input_will_pass
                              and time_delta <= cur_time - orig_time):
                            sequence_value = (
                                (cur_time - orig_time) >>
                                SEQUENCE_LOCKTIME_GRANULARITY) + 1
                        sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG
                tx.vin.append(
                    CTxIn(COutPoint(int(utxos[j]["txid"], 16),
                                    utxos[j]["vout"]),
                          nSequence=sequence_value))
                value += utxos[j]["amount"] * COIN
            # Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output
            tx_size = len(tx.serialize().hex()) // 2 + 120 * num_inputs + 50
            tx.vout.append(
                CTxOut(int(value - self.relayfee * tx_size * COIN / 1000),
                       DUMMY_P2WPKH_SCRIPT))
            rawtx = self.nodes[0].signrawtransactionwithwallet(
                tx.serialize().hex())["hex"]

            if (using_sequence_locks and not should_pass):
                # This transaction should be rejected
                assert_raises_rpc_error(-26, NOT_FINAL_ERROR,
                                        self.nodes[0].sendrawtransaction,
                                        rawtx)
            else:
                # This raw transaction should be accepted
                self.nodes[0].sendrawtransaction(rawtx)
                utxos = self.nodes[0].listunspent()
예제 #22
0
    def decoderawtransaction_asm_sighashtype(self):
        """Test decoding scripts via RPC command "decoderawtransaction".

        This test is in with the "decodescript" tests because they are testing the same "asm" script decodes.
        """

        # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output
        tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm'])

        # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs.
        # it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc
        # verify that we have not altered scriptPubKey decoding.
        tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0', rpc_result['txid'])
        assert_equal('0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae', rpc_result['vin'][0]['scriptSig']['asm'])
        assert_equal('OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])
        assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])
        txSave = CTransaction()
        txSave.deserialize(BytesIO(hex_str_to_bytes(tx)))

        # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type
        tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm'])

        # verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks
        tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])
        assert_equal('OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])

        # some more full transaction tests of varying specific scriptSigs. used instead of
        # tests in decodescript_script_sig because the decodescript RPC is specifically
        # for working on scriptPubKeys (argh!).
        push_signature = bytes_to_hex_str(txSave.vin[0].scriptSig)[2:(0x48*2+4)]
        signature = push_signature[2:]
        der_signature = signature[:-2]
        signature_sighash_decoded = der_signature + '[ALL]'
        signature_2 = der_signature + '82'
        push_signature_2 = '48' + signature_2
        signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]'

        # 1) P2PK scriptSig
        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature)
        rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize()))
        assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])

        # make sure that the sighash decodes come out correctly for a more complex / lesser used case.
        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature_2)
        rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize()))
        assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])

        # 2) multisig scriptSig
        txSave.vin[0].scriptSig = hex_str_to_bytes('00' + push_signature + push_signature_2)
        rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize()))
        assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])

        # 3) test a scriptSig that contains more than push operations.
        # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it.
        txSave.vin[0].scriptSig = hex_str_to_bytes('6a143011020701010101010101020601010101010101')
        rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize()))
        assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm'])
예제 #23
0
    def test_sequence_lock_unconfirmed_inputs(self):
        # Store height so we can easily reset the chain at the end of the test
        cur_height = self.nodes[0].getblockcount()

        # Create a mempool tx.
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2)
        tx1 = tx_from_hex(self.nodes[0].getrawtransaction(txid))
        tx1.rehash()

        # Anyone-can-spend mempool tx.
        # Sequence lock of 0 should pass.
        tx2 = CTransaction()
        tx2.nVersion = 2
        tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)]
        tx2.vout = [
            CTxOut(int(tx1.vout[0].nValue - self.relayfee * COIN),
                   DUMMY_P2WPKH_SCRIPT)
        ]
        tx2_raw = self.nodes[0].signrawtransactionwithwallet(
            tx2.serialize().hex())["hex"]
        tx2 = tx_from_hex(tx2_raw)
        tx2.rehash()

        self.nodes[0].sendrawtransaction(tx2_raw)

        # Create a spend of the 0th output of orig_tx with a sequence lock
        # of 1, and test what happens when submitting.
        # orig_tx.vout[0] must be an anyone-can-spend output
        def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock):
            sequence_value = 1
            if not use_height_lock:
                sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG

            tx = CTransaction()
            tx.nVersion = 2
            tx.vin = [
                CTxIn(COutPoint(orig_tx.sha256, 0), nSequence=sequence_value)
            ]
            tx.vout = [
                CTxOut(int(orig_tx.vout[0].nValue - relayfee * COIN),
                       DUMMY_P2WPKH_SCRIPT)
            ]
            tx.rehash()

            if (orig_tx.hash in node.getrawmempool()):
                # sendrawtransaction should fail if the tx is in the mempool
                assert_raises_rpc_error(-26, NOT_FINAL_ERROR,
                                        node.sendrawtransaction,
                                        tx.serialize().hex())
            else:
                # sendrawtransaction should succeed if the tx is not in the mempool
                node.sendrawtransaction(tx.serialize().hex())

            return tx

        test_nonzero_locks(tx2,
                           self.nodes[0],
                           self.relayfee,
                           use_height_lock=True)
        test_nonzero_locks(tx2,
                           self.nodes[0],
                           self.relayfee,
                           use_height_lock=False)

        # Now mine some blocks, but make sure tx2 doesn't get mined.
        # Use prioritisetransaction to lower the effective feerate to 0
        self.nodes[0].prioritisetransaction(txid=tx2.hash,
                                            fee_delta=int(-self.relayfee *
                                                          COIN))
        cur_time = int(time.time())
        for _ in range(10):
            self.nodes[0].setmocktime(cur_time + 600)
            self.generate(self.nodes[0], 1, sync_fun=self.no_op)
            cur_time += 600

        assert tx2.hash in self.nodes[0].getrawmempool()

        test_nonzero_locks(tx2,
                           self.nodes[0],
                           self.relayfee,
                           use_height_lock=True)
        test_nonzero_locks(tx2,
                           self.nodes[0],
                           self.relayfee,
                           use_height_lock=False)

        # Mine tx2, and then try again
        self.nodes[0].prioritisetransaction(txid=tx2.hash,
                                            fee_delta=int(self.relayfee *
                                                          COIN))

        # Advance the time on the node so that we can test timelocks
        self.nodes[0].setmocktime(cur_time + 600)
        # Save block template now to use for the reorg later
        tmpl = self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
        self.generate(self.nodes[0], 1)
        assert tx2.hash not in self.nodes[0].getrawmempool()

        # Now that tx2 is not in the mempool, a sequence locked spend should
        # succeed
        tx3 = test_nonzero_locks(tx2,
                                 self.nodes[0],
                                 self.relayfee,
                                 use_height_lock=False)
        assert tx3.hash in self.nodes[0].getrawmempool()

        self.generate(self.nodes[0], 1)
        assert tx3.hash not in self.nodes[0].getrawmempool()

        # One more test, this time using height locks
        tx4 = test_nonzero_locks(tx3,
                                 self.nodes[0],
                                 self.relayfee,
                                 use_height_lock=True)
        assert tx4.hash in self.nodes[0].getrawmempool()

        # Now try combining confirmed and unconfirmed inputs
        tx5 = test_nonzero_locks(tx4,
                                 self.nodes[0],
                                 self.relayfee,
                                 use_height_lock=True)
        assert tx5.hash not in self.nodes[0].getrawmempool()

        utxos = self.nodes[0].listunspent()
        tx5.vin.append(
            CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["vout"]),
                  nSequence=1))
        tx5.vout[0].nValue += int(utxos[0]["amount"] * COIN)
        raw_tx5 = self.nodes[0].signrawtransactionwithwallet(
            tx5.serialize().hex())["hex"]

        assert_raises_rpc_error(-26, NOT_FINAL_ERROR,
                                self.nodes[0].sendrawtransaction, raw_tx5)

        # Test mempool-BIP68 consistency after reorg
        #
        # State of the transactions in the last blocks:
        # ... -> [ tx2 ] ->  [ tx3 ]
        #         tip-1        tip
        # And currently tx4 is in the mempool.
        #
        # If we invalidate the tip, tx3 should get added to the mempool, causing
        # tx4 to be removed (fails sequence-lock).
        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
        assert tx4.hash not in self.nodes[0].getrawmempool()
        assert tx3.hash in self.nodes[0].getrawmempool()

        # Now mine 2 empty blocks to reorg out the current tip (labeled tip-1 in
        # diagram above).
        # This would cause tx2 to be added back to the mempool, which in turn causes
        # tx3 to be removed.
        for i in range(2):
            block = create_block(tmpl=tmpl, ntime=cur_time)
            block.solve()
            tip = block.sha256
            assert_equal(None if i == 1 else 'inconclusive',
                         self.nodes[0].submitblock(block.serialize().hex()))
            tmpl = self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
            tmpl['previousblockhash'] = '%x' % tip
            tmpl['transactions'] = []
            cur_time += 1

        mempool = self.nodes[0].getrawmempool()
        assert tx3.hash not in mempool
        assert tx2.hash in mempool

        # Reset the chain and get rid of the mocktimed-blocks
        self.nodes[0].setmocktime(0)
        self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height +
                                                                 1))
        self.generate(self.nodes[0], 10, sync_fun=self.no_op)
예제 #24
0
  def test_namescript_p2sh (self):
    """
    Tests how name prefixes interact with P2SH outputs and redeem scripts.
    """

    self.log.info ("Testing name prefix and P2SH interactions...")

    # This test only needs a single node and no syncing.
    node = self.nodes[0]

    name = "d/p2sh"
    value = "value"
    new = node.name_new (name)
    node.generate (12)
    self.firstupdateName (0, name, new, value)
    node.generate (1)
    baseHeight = node.getblockcount ()
    self.checkNameWithHeight (0, name, value, baseHeight)

    # Prepare some scripts and P2SH addresses we use later.  We build the
    # name script prefix for an update to our testname, so that we can build
    # P2SH redeem scripts with (or without) it.

    nameBytes = codecs.encode (name, 'ascii')
    valueBytes = codecs.encode (value, 'ascii')
    updOps = [OP_NAME_UPDATE, nameBytes, valueBytes, OP_2DROP, OP_DROP]
    anyoneOps = [OP_TRUE]

    updScript = CScript (updOps)
    anyoneScript = CScript (anyoneOps)
    updAndAnyoneScript = CScript (updOps + anyoneOps)

    anyoneAddr = self.getP2SH (0, anyoneScript)
    updAndAnyoneAddr = self.getP2SH (0, updAndAnyoneScript)

    # Send the name to the anyone-can-spend name-update script directly.
    # This is expected to update the name (verifies the update script is good).

    tx = CTransaction ()
    tx.nVersion = NAMECOIN_TX_VERSION
    data = node.name_show (name)
    tx.vin.append (CTxIn (COutPoint (int (data['txid'], 16), data['vout'])))
    tx.vout.append (CTxOut (COIN // 100, updAndAnyoneScript))
    txHex = tx.serialize ().hex ()

    txHex = node.fundrawtransaction (txHex)['hex']
    signed = node.signrawtransactionwithwallet (txHex)
    assert signed['complete']
    node.sendrawtransaction (signed['hex'])

    node.generate (1)
    self.checkNameWithHeight (0, name, value, baseHeight + 1)

    # Send the name to the anyone-can-spend P2SH address.  This should just
    # work fine and update the name.
    self.updateAnyoneCanSpendName (0, name, "value2", anyoneAddr, [])
    node.generate (1)
    self.checkNameWithHeight (0, name, "value2", baseHeight + 2)

    # Send a coin to the P2SH address with name prefix.  This should just
    # work fine but not update the name.  We should be able to spend the coin
    # again from that address.

    txid = node.sendtoaddress (updAndAnyoneAddr, 2)
    tx = node.getrawtransaction (txid)
    ind = self.rawtxOutputIndex (0, tx, updAndAnyoneAddr)
    node.generate (1)

    ins = [{"txid": txid, "vout": ind}]
    addr = node.getnewaddress ()
    out = {addr: 1}
    tx = node.createrawtransaction (ins, out)
    tx = self.setScriptSigOps (tx, 0, [updAndAnyoneScript])

    node.sendrawtransaction (tx, 0)
    node.generate (1)
    self.checkNameWithHeight (0, name, "value2", baseHeight + 2)

    found = False
    for u in node.listunspent ():
      if u['address'] == addr and u['amount'] == 1:
        found = True
        break
    if not found:
      raise AssertionError ("Coin not sent to expected address")

    # Send the name to the P2SH address with name prefix and then spend it
    # again.  Spending should work fine, and the name should just be updated
    # ordinarily; the name prefix of the redeem script should have no effect.
    self.updateAnyoneCanSpendName (0, name, "value3", updAndAnyoneAddr,
                                   [anyoneScript])
    node.generate (1)
    self.checkNameWithHeight (0, name, "value3", baseHeight + 5)
    self.updateAnyoneCanSpendName (0, name, "value4", anyoneAddr,
                                   [updAndAnyoneScript])
    node.generate (1)
    self.checkNameWithHeight (0, name, "value4", baseHeight + 6)
예제 #25
0
    def test_namescript_p2sh(self):
        """
    Tests how name prefixes interact with P2SH outputs and redeem scripts.
    """

        self.log.info("Testing name prefix and P2SH interactions...")

        # This test only needs a single node and no syncing.
        node = self.nodes[0]

        name = "d/p2sh"
        value = val("value")
        node.name_register(name, value)
        node.generate(1)
        baseHeight = node.getblockcount()
        self.checkNameWithHeight(0, name, value, baseHeight)

        # Prepare some scripts and P2SH addresses we use later.  We build the
        # name script prefix for an update to our testname, so that we can build
        # P2SH redeem scripts with (or without) it.

        nameBytes = codecs.encode(name, 'ascii')
        valueBytes = codecs.encode(value, 'ascii')
        updOps = [OP_NAME_UPDATE, nameBytes, valueBytes, OP_2DROP, OP_DROP]
        anyoneOps = [OP_TRUE]

        updScript = CScript(updOps)
        anyoneScript = CScript(anyoneOps)
        updAndAnyoneScript = CScript(updOps + anyoneOps)

        anyoneAddr = self.getP2SH(0, anyoneScript)
        updAndAnyoneAddr = self.getP2SH(0, updAndAnyoneScript)

        # Send the name to the anyone-can-spend name-update script directly.
        # This is expected to update the name (verifies the update script is good).

        tx = CTransaction()
        data = node.name_show(name)
        tx.vin.append(CTxIn(COutPoint(int(data['txid'], 16), data['vout'])))
        tx.vout.append(CTxOut(COIN // 100, updAndAnyoneScript))
        txHex = tx.serialize().hex()

        txHex = node.fundrawtransaction(txHex)['hex']
        signed = node.signrawtransactionwithwallet(txHex)
        assert signed['complete']
        node.sendrawtransaction(signed['hex'])

        node.generate(1)
        self.checkNameWithHeight(0, name, value, baseHeight + 1)

        # Send the name to the anyone-can-spend P2SH address.  This should just
        # work fine and update the name.
        self.updateAnyoneCanSpendName(0, name, val("value2"), anyoneAddr, [])
        node.generate(1)
        self.checkNameWithHeight(0, name, val("value2"), baseHeight + 2)

        # Send a coin to the P2SH address with name prefix.  This should just
        # work fine but not update the name.  We should be able to spend the coin
        # again from that address.

        txid = node.sendtoaddress(updAndAnyoneAddr, 2)
        tx = node.getrawtransaction(txid)
        ind = self.rawtxOutputIndex(0, tx, updAndAnyoneAddr)
        node.generate(1)

        ins = [{"txid": txid, "vout": ind}]
        addr = node.getnewaddress()
        out = {addr: 1}
        tx = node.createrawtransaction(ins, out)
        tx = self.setScriptSigOps(tx, 0, [updAndAnyoneScript])

        node.sendrawtransaction(tx, 0)
        node.generate(1)
        self.checkNameWithHeight(0, name, val("value2"), baseHeight + 2)

        found = False
        for u in node.listunspent():
            if u['address'] == addr and u['amount'] == 1:
                found = True
                break
        if not found:
            raise AssertionError("Coin not sent to expected address")

        # Send the name to the P2SH address with name prefix and then spend it
        # again.  Spending should work fine, and the name should just be updated
        # ordinarily; the name prefix of the redeem script should have no effect.
        self.updateAnyoneCanSpendName(0, name, val("value3"), updAndAnyoneAddr,
                                      [anyoneScript])
        node.generate(1)
        self.checkNameWithHeight(0, name, val("value3"), baseHeight + 5)
        self.updateAnyoneCanSpendName(0, name, val("value4"), anyoneAddr,
                                      [updAndAnyoneScript])
        node.generate(1)
        self.checkNameWithHeight(0, name, val("value4"), baseHeight + 6)
예제 #26
0
    def decoderawtransaction_asm_sighashtype(self):
        """Test decoding scripts via RPC command "decoderawtransaction".

        This test is in with the "decodescript" tests because they are testing the same "asm" script decodes.
        """

        # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output
        tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm'])

        # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs.
        # it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc
        # verify that we have not altered scriptPubKey decoding.
        tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0', rpc_result['txid'])
        assert_equal('0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae', rpc_result['vin'][0]['scriptSig']['asm'])
        assert_equal('OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])
        assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])
        txSave = CTransaction()
        txSave.deserialize(BytesIO(hex_str_to_bytes(tx)))

        # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type
        tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm'])

        # verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks
        tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])
        assert_equal('OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])

        # verify that names shorter than 5 bytes aren't interpreted into asm as integers (issue #140)
        tx = '0071000002c323b5df3dbd501ef8e26683749fd13f785eac6d4f4c2083196a33262605e6ec010000008b48304502207cc397996cf41a4be7ce229226c2e3862557256e372dd325dfefaba26a4a44a20221008e71fc315563d04d7d92d6e2b0ef9c5e095df50777664819623156dcf3ec1c1e0141045bc24b6e33ecbe341e8195b4e8fcb3f8c7937ca6f671f799644968dc00e82d0160c5e14b687cba83840381dda04711939a225588eb0e2401d4f14dc9d3a5ccdaffffffff882be8eb700e1c6eaef2682839293ae9d5bfacf82cee80510d4dee6eed359c98000000004847304402206c6115eb47b4f3010a6c0e79ea5ee7f036fc1da22af172c4bd39a460758bb34402204cc40302837a3a61d9b1e12a99e73572f95da7b5005e5ce842a7b8b4ba90d7f901ffffffff02e007646300000000434104fb090d04c8f110012a9f4545b6cb1f93a6f22db1b35bef7e1545a4a0aef0124cd25c522851ba2120f12b124785adc6f09b13f8eaa294cfe54a601dc75f11df29ac40420f00000000005a5303662f6a394269746d65737361676520616464726573733a20424d2d3263554755687335436a6973526975514756574447334a514a47717a5967713134356d7576a9147368feca713f2a9d7780343b74007e26a4fcfcea88ac00000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('OP_NAME_UPDATE 662f6a 4269746d65737361676520616464726573733a20424d2d3263554755687335436a6973526975514756574447334a514a47717a596771313435 OP_2DROP OP_DROP OP_DUP OP_HASH160 7368feca713f2a9d7780343b74007e26a4fcfcea OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][1]['scriptPubKey']['asm'])

        # some more full transaction tests of varying specific scriptSigs. used instead of
        # tests in decodescript_script_sig because the decodescript RPC is specifically
        # for working on scriptPubKeys (argh!).
        push_signature = txSave.vin[0].scriptSig.hex()[2:(0x48*2+4)]
        signature = push_signature[2:]
        der_signature = signature[:-2]
        signature_sighash_decoded = der_signature + '[ALL]'
        signature_2 = der_signature + '82'
        push_signature_2 = '48' + signature_2
        signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]'

        # 1) P2PK scriptSig
        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature)
        rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
        assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])

        # make sure that the sighash decodes come out correctly for a more complex / lesser used case.
        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature_2)
        rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
        assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])

        # 2) multisig scriptSig
        txSave.vin[0].scriptSig = hex_str_to_bytes('00' + push_signature + push_signature_2)
        rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
        assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])

        # 3) test a scriptSig that contains more than push operations.
        # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it.
        txSave.vin[0].scriptSig = hex_str_to_bytes('6a143011020701010101010101020601010101010101')
        rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
        assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm'])
예제 #27
0
    def test_doublespend_tree(self):
        """Doublespend of a big tree of transactions"""

        initial_nValue = 50 * COIN
        tx0_outpoint = make_utxo(self.nodes[0], initial_nValue)

        def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001 * COIN, _total_txs=None):
            if _total_txs is None:
                _total_txs = [0]
            if _total_txs[0] >= max_txs:
                return

            txout_value = (initial_value - fee) // tree_width
            if txout_value < fee:
                return

            vout = [CTxOut(txout_value, CScript([i+1]))
                    for i in range(tree_width)]
            tx = CTransaction()
            tx.vin = [CTxIn(prevout, nSequence=0)]
            tx.vout = vout
            tx_hex = tx.serialize().hex()

            assert len(tx.serialize()) < 100000
            txid = self.nodes[0].sendrawtransaction(tx_hex, 0)
            yield tx
            _total_txs[0] += 1

            txid = int(txid, 16)

            for i, txout in enumerate(tx.vout):
                for x in branch(COutPoint(txid, i), txout_value,
                                  max_txs,
                                  tree_width=tree_width, fee=fee,
                                  _total_txs=_total_txs):
                    yield x

        fee = int(0.0001 * COIN)
        n = MAX_REPLACEMENT_LIMIT
        tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
        assert_equal(len(tree_txs), n)

        # Attempt double-spend, will fail because too little fee paid
        dbl_tx = CTransaction()
        dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
        dbl_tx.vout = [CTxOut(initial_nValue - fee * n, DUMMY_P2WPKH_SCRIPT)]
        dbl_tx_hex = dbl_tx.serialize().hex()
        # This will raise an exception due to insufficient fee
        assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)

        # 1 BTC fee is enough
        dbl_tx = CTransaction()
        dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
        dbl_tx.vout = [CTxOut(initial_nValue - fee * n - 1 * COIN, DUMMY_P2WPKH_SCRIPT)]
        dbl_tx_hex = dbl_tx.serialize().hex()
        self.nodes[0].sendrawtransaction(dbl_tx_hex, 0)

        mempool = self.nodes[0].getrawmempool()

        for tx in tree_txs:
            tx.rehash()
            assert tx.hash not in mempool

        # Try again, but with more total transactions than the "max txs
        # double-spent at once" anti-DoS limit.
        for n in (MAX_REPLACEMENT_LIMIT + 1, MAX_REPLACEMENT_LIMIT * 2):
            fee = int(0.0001 * COIN)
            tx0_outpoint = make_utxo(self.nodes[0], initial_nValue)
            tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
            assert_equal(len(tree_txs), n)

            dbl_tx = CTransaction()
            dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
            dbl_tx.vout = [CTxOut(initial_nValue - 2 * fee * n, DUMMY_P2WPKH_SCRIPT)]
            dbl_tx_hex = dbl_tx.serialize().hex()
            # This will raise an exception
            assert_raises_rpc_error(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)

            for tx in tree_txs:
                tx.rehash()
                self.nodes[0].getrawtransaction(tx.hash)
예제 #28
0
    def run_test(self):
        if self.options.segwit:
            output_type = "p2sh-segwit"
        else:
            output_type = "legacy"

        # All nodes should start with 1,250 BTC:
        starting_balance = 1250
        for i in range(4):
            assert_equal(self.nodes[i].getbalance()['bitcoin'], starting_balance)
            self.nodes[i].getnewaddress()  # bug workaround, coins generated assigned to first getnewaddress!

        self.nodes[0].settxfee(.001)

        node0_address1 = self.nodes[0].getnewaddress(address_type=output_type)
        node0_txid1 = self.nodes[0].sendtoaddress(node0_address1, 1219)
        node0_tx1 = self.nodes[0].gettransaction(node0_txid1)

        node0_address2 = self.nodes[0].getnewaddress(address_type=output_type)
        node0_txid2 = self.nodes[0].sendtoaddress(node0_address2, 29)
        node0_tx2 = self.nodes[0].gettransaction(node0_txid2)

        assert_equal(self.nodes[0].getbalance()['bitcoin'],
                     starting_balance + node0_tx1["fee"]['bitcoin'] + node0_tx2["fee"]['bitcoin'])

        # Coins are sent to node1_address
        node1_address = self.nodes[1].getnewaddress()

        # Send tx1, and another transaction tx2 that won't be cloned
        txid1 = self.nodes[0].sendtoaddress(node1_address, 40)
        txid2 = self.nodes[0].sendtoaddress(node1_address, 20)

        # Construct a clone of tx1, to be malleated
        rawtx1 = self.nodes[0].getrawtransaction(txid1, 1)
        clone_inputs = [{"txid": rawtx1["vin"][0]["txid"], "vout": rawtx1["vin"][0]["vout"]}]
        clone_outputs = {rawtx1["vout"][0]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][0]["value"],
                         rawtx1["vout"][1]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][1]["value"]}
        assert_equal(rawtx1["vout"][2]["scriptPubKey"]["type"], "fee")
        clone_outputs["fee"] = rawtx1["vout"][2]["value"]
        clone_locktime = rawtx1["locktime"]
        clone_raw = self.nodes[0].createrawtransaction(clone_inputs, clone_outputs, clone_locktime)

        # createrawtransaction randomizes the order of its outputs, so swap them if necessary.
        clone_tx = CTransaction()
        clone_tx.deserialize(io.BytesIO(bytes.fromhex(clone_raw)))
        if (rawtx1["vout"][0]["value"] == 40 and clone_tx.vout[0].nValue.getAmount() != 40*COIN or rawtx1["vout"][0]["value"] != 40 and clone_tx.vout[0].nValue.getAmount() == 40*COIN):
            (clone_tx.vout[0], clone_tx.vout[1]) = (clone_tx.vout[1], clone_tx.vout[0])

        # Use a different signature hash type to sign.  This creates an equivalent but malleated clone.
        # Don't send the clone anywhere yet
        tx1_clone = self.nodes[0].signrawtransactionwithwallet(clone_tx.serialize().hex(), None, "ALL|ANYONECANPAY")
        assert_equal(tx1_clone["complete"], True)

        # Have node0 mine a block, if requested:
        if (self.options.mine_block):
            self.nodes[0].generate(1)
            sync_blocks(self.nodes[0:2])

        tx1 = self.nodes[0].gettransaction(txid1)
        tx2 = self.nodes[0].gettransaction(txid2)

        # Node0's balance should be starting balance, plus 50BTC for another
        # matured block, minus tx1 and tx2 amounts, and minus transaction fees:
        expected = starting_balance + node0_tx1["fee"]['bitcoin'] + node0_tx2["fee"]['bitcoin']
        if self.options.mine_block:
            expected += 50
        expected += tx1["amount"]['bitcoin'] + tx1["fee"]['bitcoin']
        expected += tx2["amount"]['bitcoin'] + tx2["fee"]['bitcoin']
        assert_equal(self.nodes[0].getbalance()['bitcoin'], expected)

        if self.options.mine_block:
            assert_equal(tx1["confirmations"], 1)
            assert_equal(tx2["confirmations"], 1)
        else:
            assert_equal(tx1["confirmations"], 0)
            assert_equal(tx2["confirmations"], 0)

        # Send clone and its parent to miner
        self.nodes[2].sendrawtransaction(node0_tx1["hex"])
        txid1_clone = self.nodes[2].sendrawtransaction(tx1_clone["hex"])
        if self.options.segwit:
            assert_equal(txid1, txid1_clone)
            return

        # ... mine a block...
        self.nodes[2].generate(1)

        # Reconnect the split network, and sync chain:
        connect_nodes(self.nodes[1], 2)
        self.nodes[2].sendrawtransaction(node0_tx2["hex"])
        self.nodes[2].sendrawtransaction(tx2["hex"])
        self.nodes[2].generate(1)  # Mine another block to make sure we sync
        sync_blocks(self.nodes)

        # Re-fetch transaction info:
        tx1 = self.nodes[0].gettransaction(txid1)
        tx1_clone = self.nodes[0].gettransaction(txid1_clone)
        tx2 = self.nodes[0].gettransaction(txid2)

        # Verify expected confirmations
        assert_equal(tx1["confirmations"], -2)
        assert_equal(tx1_clone["confirmations"], 2)
        assert_equal(tx2["confirmations"], 1)

        # Check node0's total balance; should be same as before the clone, + 100 BTC for 2 matured,
        # less possible orphaned matured subsidy
        expected += 100
        if (self.options.mine_block):
            expected -= 50
        assert_equal(self.nodes[0].getbalance()['bitcoin'], expected)
예제 #29
0
    def test_opt_in(self):
        """Replacing should only work if orig tx opted in"""
        tx0_outpoint = make_utxo(self.nodes[0], int(1.1 * COIN))

        # Create a non-opting in transaction
        tx1a = CTransaction()
        tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0xffffffff)]
        tx1a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
        tx1a_hex = tx1a.serialize().hex()
        tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)

        # This transaction isn't shown as replaceable
        assert_equal(self.nodes[0].getmempoolentry(tx1a_txid)['bip125-replaceable'], False)

        # Shouldn't be able to double-spend
        tx1b = CTransaction()
        tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
        tx1b.vout = [CTxOut(int(0.9 * COIN), DUMMY_P2WPKH_SCRIPT)]
        tx1b_hex = tx1b.serialize().hex()

        # This will raise an exception
        assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx1b_hex, 0)

        tx1_outpoint = make_utxo(self.nodes[0], int(1.1 * COIN))

        # Create a different non-opting in transaction
        tx2a = CTransaction()
        tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0xfffffffe)]
        tx2a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
        tx2a_hex = tx2a.serialize().hex()
        tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, 0)

        # Still shouldn't be able to double-spend
        tx2b = CTransaction()
        tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)]
        tx2b.vout = [CTxOut(int(0.9 * COIN), DUMMY_P2WPKH_SCRIPT)]
        tx2b_hex = tx2b.serialize().hex()

        # This will raise an exception
        assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx2b_hex, 0)

        # Now create a new transaction that spends from tx1a and tx2a
        # opt-in on one of the inputs
        # Transaction should be replaceable on either input

        tx1a_txid = int(tx1a_txid, 16)
        tx2a_txid = int(tx2a_txid, 16)

        tx3a = CTransaction()
        tx3a.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0xffffffff),
                    CTxIn(COutPoint(tx2a_txid, 0), nSequence=0xfffffffd)]
        tx3a.vout = [CTxOut(int(0.9 * COIN), CScript([b'c'])), CTxOut(int(0.9 * COIN), CScript([b'd']))]
        tx3a_hex = tx3a.serialize().hex()

        tx3a_txid = self.nodes[0].sendrawtransaction(tx3a_hex, 0)

        # This transaction is shown as replaceable
        assert_equal(self.nodes[0].getmempoolentry(tx3a_txid)['bip125-replaceable'], True)

        tx3b = CTransaction()
        tx3b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)]
        tx3b.vout = [CTxOut(int(0.5 * COIN), DUMMY_P2WPKH_SCRIPT)]
        tx3b_hex = tx3b.serialize().hex()

        tx3c = CTransaction()
        tx3c.vin = [CTxIn(COutPoint(tx2a_txid, 0), nSequence=0)]
        tx3c.vout = [CTxOut(int(0.5 * COIN), DUMMY_P2WPKH_SCRIPT)]
        tx3c_hex = tx3c.serialize().hex()

        self.nodes[0].sendrawtransaction(tx3b_hex, 0)
        # If tx3b was accepted, tx3c won't look like a replacement,
        # but make sure it is accepted anyway
        self.nodes[0].sendrawtransaction(tx3c_hex, 0)
예제 #30
0
    def run_test(self):

        print("Testing wallet secret recovery")
        self.test_wallet_recovery()

        print("Test blech32 python roundtrip")
        # blech/bech are aliased, both are blech32
        for addrtype in ["bech32", "blech32"]:
            addr_to_rt = self.nodes[0].getnewaddress("", addrtype)
            hrp = addr_to_rt[:2]
            assert_equal(hrp, "el")
            (witver, witprog) = decode(hrp, addr_to_rt)
            assert_equal(encode(hrp, witver, witprog), addr_to_rt)

        # Test that "blech32" gives a blinded segwit address.
        blech32_addr = self.nodes[0].getnewaddress("", "blech32")
        blech32_addr_info = self.nodes[0].getaddressinfo(blech32_addr)
        assert_equal(blech32_addr_info["iswitness"], True)
        assert_equal(blech32_addr_info["confidential"], blech32_addr)

        print("General Confidential tests")
        # Running balances
        node0 = self.nodes[0].getbalance()["bitcoin"]
        assert_equal(node0,
                     21000000)  # just making sure initialfreecoins is working
        node1 = 0
        node2 = 0

        self.nodes[0].generate(101)
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(),
                                           node0, "", "", True)
        self.nodes[0].generate(101)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, False, "bitcoin"),
                     node1)
        assert_equal(self.nodes[2].getbalance("*", 1, False, False, "bitcoin"),
                     node2)

        # Send 3 BTC from 0 to a new unconfidential address of 2 with
        # the sendtoaddress call
        address = self.nodes[2].getnewaddress()
        unconfidential_address = self.nodes[2].validateaddress(
            address)["unconfidential"]
        value0 = 3
        self.nodes[0].sendtoaddress(unconfidential_address, value0)
        self.nodes[0].generate(101)
        self.sync_all()

        node0 = node0 - value0
        node2 = node2 + value0

        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, False, "bitcoin"),
                     node1)
        assert_equal(self.nodes[2].getbalance()["bitcoin"], node2)

        # Send 5 BTC from 0 to a new address of 2 with the sendtoaddress call
        address2 = self.nodes[2].getnewaddress()
        unconfidential_address2 = self.nodes[2].validateaddress(
            address2)["unconfidential"]
        value1 = 5
        confidential_tx_id = self.nodes[0].sendtoaddress(address2, value1)
        self.nodes[0].generate(101)
        self.sync_all()

        node0 = node0 - value1
        node2 = node2 + value1

        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, False, "bitcoin"),
                     node1)
        assert_equal(self.nodes[2].getbalance()["bitcoin"], node2)

        # Send 7 BTC from 0 to the unconfidential address of 2 and 11 BTC to the
        # confidential address using the raw transaction interface
        change_address = self.nodes[0].getnewaddress()
        value2 = 7
        value3 = 11
        value23 = value2 + value3
        unspent = self.nodes[0].listunspent(1, 9999999, [], True,
                                            {"asset": "bitcoin"})
        unspent = [i for i in unspent if i['amount'] > value23]
        assert_equal(len(unspent), 1)
        fee = Decimal('0.0001')
        tx = self.nodes[0].createrawtransaction(
            [{
                "txid": unspent[0]["txid"],
                "vout": unspent[0]["vout"],
                "nValue": unspent[0]["amount"]
            }], {
                unconfidential_address: value2,
                address2: value3,
                change_address: unspent[0]["amount"] - value2 - value3 - fee,
                "fee": fee
            })
        tx = self.nodes[0].blindrawtransaction(tx)
        tx_signed = self.nodes[0].signrawtransactionwithwallet(tx)
        raw_tx_id = self.nodes[0].sendrawtransaction(tx_signed['hex'])
        self.nodes[0].generate(101)
        self.sync_all()

        node0 -= (value2 + value3)
        node2 += value2 + value3

        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, False, "bitcoin"),
                     node1)
        assert_equal(self.nodes[2].getbalance()["bitcoin"], node2)

        # Check 2's listreceivedbyaddress
        received_by_address = self.nodes[2].listreceivedbyaddress(
            0, False, False, "", "bitcoin")
        validate_by_address = [(address2, value1 + value3),
                               (address, value0 + value2)]
        assert_equal(
            sorted([(ele['address'], ele['amount'])
                    for ele in received_by_address],
                   key=lambda t: t[0]),
            sorted(validate_by_address, key=lambda t: t[0]))
        received_by_address = self.nodes[2].listreceivedbyaddress(
            0, False, False, "")
        validate_by_address = [(address2, {
            "bitcoin": value1 + value3
        }), (address, {
            "bitcoin": value0 + value2
        })]
        assert_equal(
            sorted([(ele['address'], ele['amount'])
                    for ele in received_by_address],
                   key=lambda t: t[0]),
            sorted(validate_by_address, key=lambda t: t[0]))

        # Give an auditor (node 1) a blinding key to allow her to look at
        # transaction values
        self.nodes[1].importaddress(address2)
        received_by_address = self.nodes[1].listreceivedbyaddress(
            1, False, True)
        #Node sees nothing unless it understands the values
        assert_equal(len(received_by_address), 0)
        assert_equal(
            len(self.nodes[1].listunspent(1, 9999999, [], True,
                                          {"asset": "bitcoin"})), 0)

        # Import the blinding key
        blindingkey = self.nodes[2].dumpblindingkey(address2)
        self.nodes[1].importblindingkey(address2, blindingkey)
        # Check the auditor's gettransaction and listreceivedbyaddress
        # Needs rescan to update wallet txns
        conf_tx = self.nodes[1].gettransaction(confidential_tx_id, True)
        assert_equal(conf_tx['amount']["bitcoin"], value1)

        # Make sure wallet can now deblind part of transaction
        deblinded_tx = self.nodes[1].unblindrawtransaction(
            conf_tx['hex'])['hex']
        for output in self.nodes[1].decoderawtransaction(deblinded_tx)["vout"]:
            if "value" in output and output["scriptPubKey"]["type"] != "fee":
                assert_equal(
                    output["scriptPubKey"]["addresses"][0],
                    self.nodes[1].validateaddress(address2)['unconfidential'])
                found_unblinded = True
        assert found_unblinded

        assert_equal(
            self.nodes[1].gettransaction(raw_tx_id, True)['amount']["bitcoin"],
            value3)
        assert_equal(
            self.nodes[1].gettransaction(raw_tx_id, True, False,
                                         "bitcoin")['amount'], value3)
        list_unspent = self.nodes[1].listunspent(1, 9999999, [], True,
                                                 {"asset": "bitcoin"})
        assert_equal(list_unspent[0]['amount'] + list_unspent[1]['amount'],
                     value1 + value3)
        received_by_address = self.nodes[1].listreceivedbyaddress(
            1, False, True)
        assert_equal(len(received_by_address), 1)
        assert_equal((received_by_address[0]['address'],
                      received_by_address[0]['amount']['bitcoin']),
                     (unconfidential_address2, value1 + value3))

        # Spending a single confidential output and sending it to a
        # unconfidential output is not possible with CT. Test the
        # correct behavior of blindrawtransaction.
        unspent = self.nodes[0].listunspent(1, 9999999, [], True,
                                            {"asset": "bitcoin"})
        unspent = [i for i in unspent if i['amount'] > value23]
        assert_equal(len(unspent), 1)
        tx = self.nodes[0].createrawtransaction(
            [{
                "txid": unspent[0]["txid"],
                "vout": unspent[0]["vout"],
                "nValue": unspent[0]["amount"]
            }], {
                unconfidential_address: unspent[0]["amount"] - fee,
                "fee": fee
            })

        # Test that blindrawtransaction adds an OP_RETURN output to balance blinders
        temptx = self.nodes[0].blindrawtransaction(tx)
        decodedtx = self.nodes[0].decoderawtransaction(temptx)
        assert_equal(decodedtx["vout"][-1]["scriptPubKey"]["asm"], "OP_RETURN")
        assert_equal(len(decodedtx["vout"]), 3)

        # Create same transaction but with a change/dummy output.
        # It should pass the blinding step.
        value4 = 17
        change_address = self.nodes[0].getrawchangeaddress()
        tx = self.nodes[0].createrawtransaction(
            [{
                "txid": unspent[0]["txid"],
                "vout": unspent[0]["vout"],
                "nValue": unspent[0]["amount"]
            }], {
                unconfidential_address: value4,
                change_address: unspent[0]["amount"] - value4 - fee,
                "fee": fee
            })
        tx = self.nodes[0].blindrawtransaction(tx)
        tx_signed = self.nodes[0].signrawtransactionwithwallet(tx)
        txid = self.nodes[0].sendrawtransaction(tx_signed['hex'])
        decodedtx = self.nodes[0].decoderawtransaction(tx_signed["hex"])
        self.nodes[0].generate(101)
        self.sync_all()

        unblindfound = False
        for i in range(len(decodedtx["vout"])):
            txout = self.nodes[0].gettxout(txid, i)
            if txout is not None and "asset" in txout:
                unblindfound = True

        if unblindfound == False:
            raise Exception(
                "No unconfidential output detected when one should exist")

        node0 -= value4
        node2 += value4
        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, False, "bitcoin"),
                     node1)
        assert_equal(self.nodes[2].getbalance()["bitcoin"], node2)

        # Testing wallet's ability to deblind its own outputs
        addr = self.nodes[0].getnewaddress()
        addr2 = self.nodes[0].getnewaddress()
        # We add two to-blind outputs, fundraw adds an already-blinded change output
        # If we only add one, the newly blinded will be 0-blinded because input = -output
        raw = self.nodes[0].createrawtransaction([], {
            addr: Decimal('1.1'),
            addr2: 1
        })
        funded = self.nodes[0].fundrawtransaction(raw)
        # fund again to make sure no blinded outputs were created (would fail)
        funded = self.nodes[0].fundrawtransaction(funded["hex"])
        blinded = self.nodes[0].blindrawtransaction(funded["hex"])
        # blind again to make sure we know output blinders
        blinded2 = self.nodes[0].blindrawtransaction(blinded)
        # then sign and send
        signed = self.nodes[0].signrawtransactionwithwallet(blinded2)
        self.nodes[0].sendrawtransaction(signed["hex"])

        # Aside: Check all outputs after fundraw are properly marked for blinding
        fund_decode = self.nodes[0].decoderawtransaction(funded["hex"])
        for output in fund_decode["vout"][:-1]:
            assert "asset" in output
            assert "value" in output
            assert output["scriptPubKey"]["type"] != "fee"
            assert output["commitmentnonce_fully_valid"]
        assert fund_decode["vout"][-1]["scriptPubKey"]["type"] == "fee"
        assert not fund_decode["vout"][-1]["commitmentnonce_fully_valid"]

        # Also check that all fundraw outputs marked for blinding are blinded later
        for blind_tx in [blinded, blinded2]:
            blind_decode = self.nodes[0].decoderawtransaction(blind_tx)
            for output in blind_decode["vout"][:-1]:
                assert "asset" not in output
                assert "value" not in output
                assert output["scriptPubKey"]["type"] != "fee"
                assert output["commitmentnonce_fully_valid"]
            assert blind_decode["vout"][-1]["scriptPubKey"]["type"] == "fee"
            assert "asset" in blind_decode["vout"][-1]
            assert "value" in blind_decode["vout"][-1]
            assert not blind_decode["vout"][-1]["commitmentnonce_fully_valid"]

        # Check createblindedaddress functionality
        blinded_addr = self.nodes[0].getnewaddress()
        validated_addr = self.nodes[0].validateaddress(blinded_addr)
        blinding_pubkey = self.nodes[0].validateaddress(
            blinded_addr)["confidential_key"]
        blinding_key = self.nodes[0].dumpblindingkey(blinded_addr)
        assert_equal(
            blinded_addr, self.nodes[1].createblindedaddress(
                validated_addr["unconfidential"], blinding_pubkey))

        # If a blinding key is over-ridden by a newly imported one, funds may be unaccounted for
        new_addr = self.nodes[0].getnewaddress()
        new_validated = self.nodes[0].validateaddress(new_addr)
        self.nodes[2].sendtoaddress(new_addr, 1)
        self.sync_all()
        diff_blind = self.nodes[1].createblindedaddress(
            new_validated["unconfidential"], blinding_pubkey)
        assert_equal(
            len(self.nodes[0].listunspent(0, 0,
                                          [new_validated["unconfidential"]])),
            1)
        self.nodes[0].importblindingkey(diff_blind, blinding_key)
        # CT values for this wallet transaction  have been cached via importblindingkey
        # therefore result will be same even though we change blinding keys
        assert_equal(
            len(self.nodes[0].listunspent(0, 0,
                                          [new_validated["unconfidential"]])),
            1)

        # Confidential Assets Tests

        print("Assets tests...")

        # Bitcoin is the first issuance
        assert_equal(self.nodes[0].listissuances()[0]["assetlabel"], "bitcoin")
        assert_equal(len(self.nodes[0].listissuances()), 1)

        # Unblinded issuance of asset
        issued = self.nodes[0].issueasset(1, 1, False)
        self.nodes[0].reissueasset(issued["asset"], 1)

        # Compare resulting fields with getrawtransaction
        raw_details = self.nodes[0].getrawtransaction(issued["txid"], 1)
        assert_equal(
            issued["entropy"],
            raw_details["vin"][issued["vin"]]["issuance"]["assetEntropy"])
        assert_equal(issued["asset"],
                     raw_details["vin"][issued["vin"]]["issuance"]["asset"])
        assert_equal(issued["token"],
                     raw_details["vin"][issued["vin"]]["issuance"]["token"])

        self.nodes[0].generate(1)
        self.sync_all()

        issued2 = self.nodes[0].issueasset(2, 1)
        test_asset = issued2["asset"]
        assert_equal(self.nodes[0].getwalletinfo()['balance'][test_asset],
                     Decimal(2))
        assert test_asset not in self.nodes[1].getwalletinfo()['balance']

        # Assets balance checking, note that accounts are completely ignored because
        # balance queries with accounts are horrifically broken upstream
        assert_equal(self.nodes[0].getbalance("*", 0, False, False, "bitcoin"),
                     self.nodes[0].getbalance("*", 0, False, False, "bitcoin"))
        assert_equal(self.nodes[0].getbalance("*", 0, False, False)["bitcoin"],
                     self.nodes[0].getbalance("*", 0, False, False, "bitcoin"))
        assert_equal(self.nodes[0].getwalletinfo()['balance']['bitcoin'],
                     self.nodes[0].getbalance("*", 0, False, False, "bitcoin"))

        # Send some bitcoin and other assets over as well to fund wallet
        addr = self.nodes[2].getnewaddress()
        txid = self.nodes[0].sendtoaddress(addr, 5)
        # Make sure we're doing 52 bits of hiding which covers 21M BTC worth
        assert_equal(
            self.nodes[0].getrawtransaction(txid, 1)["vout"][0]["ct-bits"], 52)
        self.nodes[0].sendmany("", {
            addr: 1,
            self.nodes[2].getnewaddress(): 13
        }, 0, "", [], False, 1, "UNSET", {addr: test_asset})

        self.sync_all()

        # Should have exactly 1 in change(trusted, though not confirmed) after sending one off
        assert_equal(
            self.nodes[0].getbalance("*", 0, False, False, test_asset), 1)
        assert_equal(self.nodes[2].getunconfirmedbalance()[test_asset],
                     Decimal(1))

        b_utxos = self.nodes[2].listunspent(0, 0, [], True,
                                            {"asset": "bitcoin"})
        t_utxos = self.nodes[2].listunspent(0, 0, [], True,
                                            {"asset": test_asset})

        assert_equal(len(self.nodes[2].listunspent(0, 0, [])),
                     len(b_utxos) + len(t_utxos))

        # Now craft a blinded transaction via raw api
        rawaddrs = []
        for i in range(2):
            rawaddrs.append(self.nodes[1].getnewaddress())
        raw_assets = self.nodes[2].createrawtransaction(
            [{
                "txid": b_utxos[0]['txid'],
                "vout": b_utxos[0]['vout'],
                "nValue": b_utxos[0]['amount']
            }, {
                "txid": b_utxos[1]['txid'],
                "vout": b_utxos[1]['vout'],
                "nValue": b_utxos[1]['amount'],
                "asset": b_utxos[1]['asset']
            }, {
                "txid": t_utxos[0]['txid'],
                "vout": t_utxos[0]['vout'],
                "nValue": t_utxos[0]['amount'],
                "asset": t_utxos[0]['asset']
            }], {
                rawaddrs[1]:
                Decimal(t_utxos[0]['amount']),
                rawaddrs[0]:
                Decimal(b_utxos[0]['amount'] + b_utxos[1]['amount'] -
                        Decimal("0.01")),
                "fee":
                Decimal("0.01")
            }, 0, False, {
                rawaddrs[0]: b_utxos[0]['asset'],
                rawaddrs[1]: t_utxos[0]['asset'],
                "fee": b_utxos[0]['asset']
            })

        # Sign unblinded, then blinded
        signed_assets = self.nodes[2].signrawtransactionwithwallet(raw_assets)
        blind_assets = self.nodes[2].blindrawtransaction(raw_assets)
        signed_assets = self.nodes[2].signrawtransactionwithwallet(
            blind_assets)

        # And finally send
        self.nodes[2].sendrawtransaction(signed_assets['hex'])
        self.nodes[2].generate(101)
        self.sync_all()

        issuancedata = self.nodes[2].issueasset(
            0, Decimal('0.00000006'))  #0 of asset, 6 reissuance token

        # Node 2 will send node 1 a reissuance token, both will generate assets
        self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(),
                                    Decimal('0.00000001'), "", "", False,
                                    False, 1, "UNSET", False,
                                    issuancedata["token"])
        # node 1 needs to know about a (re)issuance to reissue itself
        self.nodes[1].importaddress(self.nodes[2].gettransaction(
            issuancedata["txid"])["details"][0]["address"])
        # also send some bitcoin
        self.nodes[2].generate(1)
        self.sync_all()

        self.nodes[1].reissueasset(issuancedata["asset"], Decimal('0.05'))
        self.nodes[2].reissueasset(issuancedata["asset"], Decimal('0.025'))
        self.nodes[1].generate(1)
        self.sync_all()

        # Check for value accounting when asset issuance is null but token not, ie unblinded
        # HACK: Self-send to sweep up bitcoin inputs into blinded output.
        # We were hitting https://github.com/ElementsProject/elements/issues/473 for the following issuance
        self.nodes[0].sendtoaddress(
            self.nodes[0].getnewaddress(),
            self.nodes[0].getwalletinfo()["balance"]["bitcoin"], "", "", True)
        issued = self.nodes[0].issueasset(0, 1, False)
        walletinfo = self.nodes[0].getwalletinfo()
        assert issued["asset"] not in walletinfo["balance"]
        assert_equal(walletinfo["balance"][issued["token"]], Decimal(1))
        assert issued["asset"] not in walletinfo["unconfirmed_balance"]
        assert issued["token"] not in walletinfo["unconfirmed_balance"]

        # Check for value when receiving different assets by same address.
        self.nodes[0].sendtoaddress(unconfidential_address2,
                                    Decimal('0.00000001'), "", "", False,
                                    False, 1, "UNSET", False, test_asset)
        self.nodes[0].sendtoaddress(unconfidential_address2,
                                    Decimal('0.00000002'), "", "", False,
                                    False, 1, "UNSET", False, test_asset)
        self.nodes[0].generate(1)
        self.sync_all()
        received_by_address = self.nodes[1].listreceivedbyaddress(
            0, False, True)
        multi_asset_amount = [
            x for x in received_by_address
            if x['address'] == unconfidential_address2
        ][0]['amount']
        assert_equal(multi_asset_amount['bitcoin'], value1 + value3)
        assert_equal(multi_asset_amount[test_asset], Decimal('0.00000003'))

        # Check blinded multisig functionality and partial blinding functionality

        # Get two pubkeys
        blinded_addr = self.nodes[0].getnewaddress()
        pubkey = self.nodes[0].getaddressinfo(blinded_addr)["pubkey"]
        blinded_addr2 = self.nodes[1].getnewaddress()
        pubkey2 = self.nodes[1].getaddressinfo(blinded_addr2)["pubkey"]
        pubkeys = [pubkey, pubkey2]
        # Add multisig address
        unconfidential_addr = self.nodes[0].addmultisigaddress(
            2, pubkeys)["address"]
        self.nodes[1].addmultisigaddress(2, pubkeys)
        self.nodes[0].importaddress(unconfidential_addr)
        self.nodes[1].importaddress(unconfidential_addr)
        # Use blinding key from node 0's original getnewaddress call
        blinding_pubkey = self.nodes[0].getaddressinfo(
            blinded_addr)["confidential_key"]
        blinding_key = self.nodes[0].dumpblindingkey(blinded_addr)
        # Create blinded address from p2sh address and import corresponding privkey
        blinded_multisig_addr = self.nodes[0].createblindedaddress(
            unconfidential_addr, blinding_pubkey)
        self.nodes[0].importblindingkey(blinded_multisig_addr, blinding_key)

        # Issue new asset, to use different assets in one transaction when doing
        # partial blinding. Just to make these tests a bit more elaborate :-)
        issued3 = self.nodes[2].issueasset(1, 0)
        self.nodes[2].generate(1)
        self.sync_all()
        node2_balance = self.nodes[2].getbalance()
        assert issued3['asset'] in node2_balance
        assert_equal(node2_balance[issued3['asset']], Decimal(1))

        # Send asset to blinded multisig address and check that it was received
        self.nodes[2].sendtoaddress(address=blinded_multisig_addr,
                                    amount=1,
                                    assetlabel=issued3['asset'])
        self.sync_all()
        # We will use this multisig UTXO in our partially-blinded transaction,
        # and will also check that multisig UTXO can be successfully spent
        # after the transaction is signed by node1 and node0 in succession.
        unspent_asset = self.nodes[0].listunspent(0, 0, [unconfidential_addr],
                                                  True,
                                                  {"asset": issued3['asset']})
        assert_equal(len(unspent_asset), 1)
        assert issued3['asset'] not in self.nodes[2].getbalance()

        # Create new UTXO on node0 to be used in our partially-blinded transaction
        blinded_addr = self.nodes[0].getnewaddress()
        addr = self.nodes[0].validateaddress(blinded_addr)["unconfidential"]
        self.nodes[0].sendtoaddress(blinded_addr, 0.1)
        unspent = self.nodes[0].listunspent(0, 0, [addr])
        assert_equal(len(unspent), 1)

        # Create new UTXO on node1 to be used in our partially-blinded transaction
        blinded_addr2 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[1].validateaddress(blinded_addr2)["unconfidential"]
        self.nodes[1].sendtoaddress(blinded_addr2, 0.11)
        unspent2 = self.nodes[1].listunspent(0, 0, [addr2])
        assert_equal(len(unspent2), 1)

        # The transaction will have three non-fee outputs
        dst_addr = self.nodes[0].getnewaddress()
        dst_addr2 = self.nodes[1].getnewaddress()
        dst_addr3 = self.nodes[2].getnewaddress()

        # Inputs are selected up front
        inputs = [{
            "txid": unspent2[0]["txid"],
            "vout": unspent2[0]["vout"]
        }, {
            "txid": unspent[0]["txid"],
            "vout": unspent[0]["vout"]
        }, {
            "txid": unspent_asset[0]["txid"],
            "vout": unspent_asset[0]["vout"]
        }]

        # Create one part of the transaction to partially blind
        rawtx = self.nodes[0].createrawtransaction(
            inputs[:1], {dst_addr2: Decimal("0.01")})

        # Create another part of the transaction to partially blind
        rawtx2 = self.nodes[0].createrawtransaction(
            inputs[1:], {
                dst_addr: Decimal("0.1"),
                dst_addr3: Decimal("1.0")
            }, 0, False, {
                dst_addr: unspent[0]['asset'],
                dst_addr3: unspent_asset[0]['asset']
            })

        sum_i = unspent2[0]["amount"] + unspent[0]["amount"]
        sum_o = 0.01 + 0.10 + 0.1
        assert_equal(int(round(sum_i * COIN)), int(round(sum_o * COIN)))

        # Blind the first part of the transaction - we need to supply the
        # assetcommmitments for all of the inputs, for the surjectionproof
        # to be valid after we combine the transactions
        blindtx = self.nodes[1].blindrawtransaction(rawtx, True, [
            unspent2[0]['assetcommitment'], unspent[0]['assetcommitment'],
            unspent_asset[0]['assetcommitment']
        ])

        # Combine the transactions

        # Blinded, but incomplete transaction.
        # 1 inputs and 1 output, but no fee output, and
        # it was blinded with 3 asset commitments, that means
        # the final transaction should have 3 inputs.
        btx = CTransaction()
        btx.deserialize(io.BytesIO(hex_str_to_bytes(blindtx)))

        # Unblinded transaction, with 2 inputs and 2 outputs.
        # We will add them to the other transaction to make it complete.
        ubtx = CTransaction()
        ubtx.deserialize(io.BytesIO(hex_str_to_bytes(rawtx2)))

        # We will add outputs of unblinded transaction
        # on top of inputs and outputs of the blinded, but incomplete transaction.
        # We also append empty witness instances to make witness arrays match
        # vin/vout arrays
        btx.vin.append(ubtx.vin[0])
        btx.wit.vtxinwit.append(CTxInWitness())
        btx.vout.append(ubtx.vout[0])
        btx.wit.vtxoutwit.append(CTxOutWitness())
        btx.vin.append(ubtx.vin[1])
        btx.wit.vtxinwit.append(CTxInWitness())
        btx.vout.append(ubtx.vout[1])
        btx.wit.vtxoutwit.append(CTxOutWitness())
        # Add explicit fee output
        btx.vout.append(
            CTxOut(nValue=CTxOutValue(10000000),
                   nAsset=CTxOutAsset(BITCOIN_ASSET_OUT)))
        btx.wit.vtxoutwit.append(CTxOutWitness())

        # Input 0 is bitcoin asset (already blinded)
        # Input 1 is also bitcoin asset
        # Input 2 is our new asset

        # Blind with wrong order of assetcommitments - such transaction should be rejected
        blindtx = self.nodes[0].blindrawtransaction(
            btx.serialize().hex(), True, [
                unspent_asset[0]['assetcommitment'],
                unspent[0]['assetcommitment'], unspent2[0]['assetcommitment']
            ])

        stx2 = self.nodes[1].signrawtransactionwithwallet(blindtx)
        stx = self.nodes[0].signrawtransactionwithwallet(stx2['hex'])
        self.sync_all()

        assert_raises_rpc_error(-26, "bad-txns-in-ne-out",
                                self.nodes[2].sendrawtransaction, stx['hex'])

        # Blind with correct order of assetcommitments
        blindtx = self.nodes[0].blindrawtransaction(
            btx.serialize().hex(), True, [
                unspent2[0]['assetcommitment'], unspent[0]['assetcommitment'],
                unspent_asset[0]['assetcommitment']
            ])

        stx2 = self.nodes[1].signrawtransactionwithwallet(blindtx)
        stx = self.nodes[0].signrawtransactionwithwallet(stx2['hex'])
        txid = self.nodes[2].sendrawtransaction(stx['hex'])
        self.nodes[2].generate(1)
        assert self.nodes[2].gettransaction(txid)['confirmations'] == 1
        self.sync_all()

        # Check that the sent asset has reached its destination
        unconfidential_dst_addr3 = self.nodes[2].validateaddress(
            dst_addr3)["unconfidential"]
        unspent_asset2 = self.nodes[2].listunspent(1, 1,
                                                   [unconfidential_dst_addr3],
                                                   True,
                                                   {"asset": issued3['asset']})
        assert_equal(len(unspent_asset2), 1)
        assert_equal(unspent_asset2[0]['amount'], Decimal(1))
        # And that the balance was correctly updated
        assert_equal(self.nodes[2].getbalance()[issued3['asset']], Decimal(1))

        # Basic checks of rawblindrawtransaction functionality
        blinded_addr = self.nodes[0].getnewaddress()
        addr = self.nodes[0].validateaddress(blinded_addr)["unconfidential"]
        self.nodes[0].sendtoaddress(blinded_addr, 1)
        self.nodes[0].sendtoaddress(blinded_addr, 3)
        unspent = self.nodes[0].listunspent(0, 0)
        rawtx = self.nodes[0].createrawtransaction(
            [{
                "txid": unspent[0]["txid"],
                "vout": unspent[0]["vout"]
            }, {
                "txid": unspent[1]["txid"],
                "vout": unspent[1]["vout"]
            }], {
                addr:
                unspent[0]["amount"] + unspent[1]["amount"] - Decimal("0.2"),
                "fee": Decimal("0.2")
            })
        # Blinding will fail with 2 blinded inputs and 0 blinded outputs
        # since it has no notion of a wallet to fill in a 0-value OP_RETURN output
        try:
            self.nodes[0].rawblindrawtransaction(
                rawtx,
                [unspent[0]["amountblinder"], unspent[1]["amountblinder"]],
                [unspent[0]["amount"], unspent[1]["amount"]],
                [unspent[0]["asset"], unspent[1]["asset"]],
                [unspent[0]["assetblinder"], unspent[1]["assetblinder"]])
            raise AssertionError(
                "Shouldn't be able to blind 2 input 0 output transaction via rawblindraw"
            )
        except JSONRPCException:
            pass

        # Blinded destination added, can blind, sign and send
        rawtx = self.nodes[0].createrawtransaction(
            [{
                "txid": unspent[0]["txid"],
                "vout": unspent[0]["vout"]
            }, {
                "txid": unspent[1]["txid"],
                "vout": unspent[1]["vout"]
            }], {
                blinded_addr:
                unspent[0]["amount"] + unspent[1]["amount"] - Decimal("0.002"),
                "fee":
                Decimal("0.002")
            })
        signtx = self.nodes[0].signrawtransactionwithwallet(rawtx)

        try:
            self.nodes[0].sendrawtransaction(signtx["hex"])
            raise AssertionError(
                "Shouldn't be able to send unblinded tx with emplaced pubkey in output without additional argument"
            )
        except JSONRPCException:
            pass

        # Make sure RPC throws when an invalid blinding factor is provided.
        bad_blinder = 'FF' * 32
        assert_raises_rpc_error(
            -8,
            "Unable to blind transaction: Are you sure each asset type to blind is represented in the inputs?",
            self.nodes[0].rawblindrawtransaction, rawtx,
            [unspent[0]["amountblinder"], bad_blinder],
            [unspent[0]["amount"], unspent[1]["amount"]],
            [unspent[0]["asset"], unspent[1]["asset"]],
            [unspent[0]["assetblinder"], unspent[1]["assetblinder"]])
        assert_raises_rpc_error(
            -8,
            "Unable to blind transaction: Are you sure each asset type to blind is represented in the inputs?",
            self.nodes[0].rawblindrawtransaction, rawtx,
            [unspent[0]["amountblinder"], unspent[1]["amountblinder"]],
            [unspent[0]["amount"], unspent[1]["amount"]],
            [unspent[0]["asset"], unspent[1]["asset"]],
            [unspent[0]["assetblinder"], bad_blinder])

        blindtx = self.nodes[0].rawblindrawtransaction(
            rawtx, [unspent[0]["amountblinder"], unspent[1]["amountblinder"]],
            [unspent[0]["amount"], unspent[1]["amount"]],
            [unspent[0]["asset"], unspent[1]["asset"]],
            [unspent[0]["assetblinder"], unspent[1]["assetblinder"]])
        signtx = self.nodes[0].signrawtransactionwithwallet(blindtx)
        txid = self.nodes[0].sendrawtransaction(signtx["hex"])
        for output in self.nodes[0].decoderawtransaction(blindtx)["vout"]:
            if "asset" in output and output["scriptPubKey"]["type"] != "fee":
                raise AssertionError("An unblinded output exists")

        # Test fundrawtransaction with multiple assets
        issue = self.nodes[0].issueasset(1, 0)
        assetaddr = self.nodes[0].getnewaddress()
        rawtx = self.nodes[0].createrawtransaction(
            [], {
                assetaddr: 1,
                self.nodes[0].getnewaddress(): 2
            }, 0, False, {assetaddr: issue["asset"]})
        funded = self.nodes[0].fundrawtransaction(rawtx)
        blinded = self.nodes[0].blindrawtransaction(funded["hex"])
        signed = self.nodes[0].signrawtransactionwithwallet(blinded)
        txid = self.nodes[0].sendrawtransaction(signed["hex"])

        # Test fundrawtransaction with multiple inputs, creating > vout.size change
        rawtx = self.nodes[0].createrawtransaction(
            [{
                "txid": txid,
                "vout": 0
            }, {
                "txid": txid,
                "vout": 1
            }], {self.nodes[0].getnewaddress(): 5})
        funded = self.nodes[0].fundrawtransaction(rawtx)
        blinded = self.nodes[0].blindrawtransaction(funded["hex"])
        signed = self.nodes[0].signrawtransactionwithwallet(blinded)
        txid = self.nodes[0].sendrawtransaction(signed["hex"])

        # Test corner case where wallet appends a OP_RETURN output, yet doesn't blind it
        # due to the fact that the output value is 0-value and input pedersen commitments
        # self-balance. This is rare corner case, but ok.
        unblinded = self.nodes[0].validateaddress(
            self.nodes[0].getnewaddress())["unconfidential"]
        self.nodes[0].sendtoaddress(unblinded,
                                    self.nodes[0].getbalance()["bitcoin"], "",
                                    "", True)
        # Make tx with blinded destination and change outputs only
        self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(),
                                    self.nodes[0].getbalance()["bitcoin"] / 2)
        # Send back again, this transaction should have 3 outputs, all unblinded
        txid = self.nodes[0].sendtoaddress(
            unblinded, self.nodes[0].getbalance()["bitcoin"], "", "", True)
        outputs = self.nodes[0].getrawtransaction(txid, 1)["vout"]
        assert_equal(len(outputs), 3)
        assert "value" in outputs[0] and "value" in outputs[
            1] and "value" in outputs[2]
        assert_equal(outputs[2]["scriptPubKey"]["type"], 'nulldata')

        # Test burn argument in createrawtransaction
        raw_burn1 = self.nodes[0].createrawtransaction(
            [], {
                self.nodes[0].getnewaddress(): 1,
                "burn": 2
            })
        decode_burn1 = self.nodes[0].decoderawtransaction(raw_burn1)
        assert_equal(len(decode_burn1["vout"]), 2)
        found_pay = False
        found_burn = False
        for output in decode_burn1["vout"]:
            if output["scriptPubKey"]["asm"] == "OP_RETURN":
                found_burn = True
                if output["asset"] != self.nodes[0].dumpassetlabels(
                )["bitcoin"]:
                    raise Exception(
                        "Burn should have been bitcoin(policyAsset)")
            if output["scriptPubKey"]["type"] == "witness_v0_keyhash":
                found_pay = True
        assert found_pay and found_burn

        raw_burn2 = self.nodes[0].createrawtransaction(
            [], {
                self.nodes[0].getnewaddress(): 1,
                "burn": 2
            }, 101, False, {"burn": "deadbeef" * 8})
        decode_burn2 = self.nodes[0].decoderawtransaction(raw_burn2)
        assert_equal(len(decode_burn2["vout"]), 2)
        found_pay = False
        found_burn = False
        for output in decode_burn2["vout"]:
            if output["scriptPubKey"]["asm"] == "OP_RETURN":
                found_burn = True
                if output["asset"] != "deadbeef" * 8:
                    raise Exception("Burn should have been deadbeef")
            if output["scriptPubKey"]["type"] == "witness_v0_keyhash":
                found_pay = True
        assert found_pay and found_burn
예제 #31
0
    def run_test(self):
        self.generate(self.nodes[0], 161)  # block 161

        self.log.info(
            "Verify sigops are counted in GBT with pre-BIP141 rules before the fork"
        )
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
        assert_equal(tmpl['sizelimit'], 1000000)
        assert 'weightlimit' not in tmpl
        assert_equal(tmpl['sigoplimit'], 20000)
        assert_equal(tmpl['transactions'][0]['hash'], txid)
        assert_equal(tmpl['transactions'][0]['sigops'], 2)
        assert '!segwit' not in tmpl['rules']
        self.generate(self.nodes[0], 1)  # block 162

        balance_presetup = self.nodes[0].getbalance()
        self.pubkey = []
        p2sh_ids = [
        ]  # p2sh_ids[NODE][TYPE] is an array of txids that spend to P2WPKH (TYPE=0) or P2WSH (TYPE=1) scripts to an address for NODE embedded in p2sh
        wit_ids = [
        ]  # wit_ids[NODE][TYPE] is an array of txids that spend to P2WPKH (TYPE=0) or P2WSH (TYPE=1) scripts to an address for NODE via bare witness
        for i in range(3):
            key = get_generate_key()
            self.pubkey.append(key.pubkey)

            multiscript = keys_to_multisig_script([self.pubkey[-1]])
            p2sh_ms_addr = self.nodes[i].createmultisig(
                1, [self.pubkey[-1]], 'p2sh-segwit')['address']
            bip173_ms_addr = self.nodes[i].createmultisig(
                1, [self.pubkey[-1]], 'bech32')['address']
            assert_equal(p2sh_ms_addr, script_to_p2sh_p2wsh(multiscript))
            assert_equal(bip173_ms_addr, script_to_p2wsh(multiscript))

            p2sh_ms_desc = descsum_create(f"sh(wsh(multi(1,{key.privkey})))")
            bip173_ms_desc = descsum_create(f"wsh(multi(1,{key.privkey}))")
            assert_equal(self.nodes[i].deriveaddresses(p2sh_ms_desc)[0],
                         p2sh_ms_addr)
            assert_equal(self.nodes[i].deriveaddresses(bip173_ms_desc)[0],
                         bip173_ms_addr)

            sh_wpkh_desc = descsum_create(f"sh(wpkh({key.privkey}))")
            wpkh_desc = descsum_create(f"wpkh({key.privkey})")
            assert_equal(self.nodes[i].deriveaddresses(sh_wpkh_desc)[0],
                         key.p2sh_p2wpkh_addr)
            assert_equal(self.nodes[i].deriveaddresses(wpkh_desc)[0],
                         key.p2wpkh_addr)

            if self.options.descriptors:
                res = self.nodes[i].importdescriptors([
                    {
                        "desc": p2sh_ms_desc,
                        "timestamp": "now"
                    },
                    {
                        "desc": bip173_ms_desc,
                        "timestamp": "now"
                    },
                    {
                        "desc": sh_wpkh_desc,
                        "timestamp": "now"
                    },
                    {
                        "desc": wpkh_desc,
                        "timestamp": "now"
                    },
                ])
            else:
                # The nature of the legacy wallet is that this import results in also adding all of the necessary scripts
                res = self.nodes[i].importmulti([
                    {
                        "desc": p2sh_ms_desc,
                        "timestamp": "now"
                    },
                ])
            assert all([r["success"] for r in res])

            p2sh_ids.append([])
            wit_ids.append([])
            for _ in range(2):
                p2sh_ids[i].append([])
                wit_ids[i].append([])

        for _ in range(5):
            for n in range(3):
                for v in range(2):
                    wit_ids[n][v].append(
                        send_to_witness(v, self.nodes[0],
                                        find_spendable_utxo(self.nodes[0], 50),
                                        self.pubkey[n], False,
                                        Decimal("49.999")))
                    p2sh_ids[n][v].append(
                        send_to_witness(v, self.nodes[0],
                                        find_spendable_utxo(self.nodes[0], 50),
                                        self.pubkey[n], True,
                                        Decimal("49.999")))

        self.generate(self.nodes[0], 1)  # block 163

        # Make sure all nodes recognize the transactions as theirs
        assert_equal(self.nodes[0].getbalance(),
                     balance_presetup - 60 * 50 + 20 * Decimal("49.999") + 50)
        assert_equal(self.nodes[1].getbalance(), 20 * Decimal("49.999"))
        assert_equal(self.nodes[2].getbalance(), 20 * Decimal("49.999"))

        self.generate(self.nodes[0], 260)  # block 423

        self.log.info(
            "Verify witness txs are skipped for mining before the fork")
        self.skip_mine(self.nodes[2], wit_ids[NODE_2][P2WPKH][0],
                       True)  # block 424
        self.skip_mine(self.nodes[2], wit_ids[NODE_2][P2WSH][0],
                       True)  # block 425
        self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][P2WPKH][0],
                       True)  # block 426
        self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][P2WSH][0],
                       True)  # block 427

        self.log.info(
            "Verify unsigned p2sh witness txs without a redeem script are invalid"
        )
        self.fail_accept(
            self.nodes[2],
            "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)",
            p2sh_ids[NODE_2][P2WPKH][1],
            sign=False)
        self.fail_accept(
            self.nodes[2],
            "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)",
            p2sh_ids[NODE_2][P2WSH][1],
            sign=False)

        self.generate(self.nodes[2], 4)  # blocks 428-431

        self.log.info(
            "Verify previous witness txs skipped for mining can now be mined")
        assert_equal(len(self.nodes[2].getrawmempool()), 4)
        blockhash = self.generate(
            self.nodes[2],
            1)[0]  # block 432 (first block with new rules; 432 = 144 * 3)
        assert_equal(len(self.nodes[2].getrawmempool()), 0)
        segwit_tx_list = self.nodes[2].getblock(blockhash)["tx"]
        assert_equal(len(segwit_tx_list), 5)

        self.log.info(
            "Verify default node can't accept txs with missing witness")
        # unsigned, no scriptsig
        self.fail_accept(
            self.nodes[0],
            "non-mandatory-script-verify-flag (Witness program hash mismatch)",
            wit_ids[NODE_0][P2WPKH][0],
            sign=False)
        self.fail_accept(
            self.nodes[0],
            "non-mandatory-script-verify-flag (Witness program was passed an empty witness)",
            wit_ids[NODE_0][P2WSH][0],
            sign=False)
        self.fail_accept(
            self.nodes[0],
            "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)",
            p2sh_ids[NODE_0][P2WPKH][0],
            sign=False)
        self.fail_accept(
            self.nodes[0],
            "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)",
            p2sh_ids[NODE_0][P2WSH][0],
            sign=False)
        # unsigned with redeem script
        self.fail_accept(
            self.nodes[0],
            "non-mandatory-script-verify-flag (Witness program hash mismatch)",
            p2sh_ids[NODE_0][P2WPKH][0],
            sign=False,
            redeem_script=witness_script(False, self.pubkey[0]))
        self.fail_accept(
            self.nodes[0],
            "non-mandatory-script-verify-flag (Witness program was passed an empty witness)",
            p2sh_ids[NODE_0][P2WSH][0],
            sign=False,
            redeem_script=witness_script(True, self.pubkey[0]))

        self.log.info(
            "Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag"
        )
        assert self.nodes[2].getblock(
            blockhash, False) != self.nodes[0].getblock(blockhash, False)
        assert self.nodes[1].getblock(blockhash,
                                      False) == self.nodes[2].getblock(
                                          blockhash, False)

        for tx_id in segwit_tx_list:
            tx = tx_from_hex(self.nodes[2].gettransaction(tx_id)["hex"])
            assert self.nodes[2].getrawtransaction(
                tx_id, False, blockhash) != self.nodes[0].getrawtransaction(
                    tx_id, False, blockhash)
            assert self.nodes[1].getrawtransaction(
                tx_id, False, blockhash) == self.nodes[2].getrawtransaction(
                    tx_id, False, blockhash)
            assert self.nodes[0].getrawtransaction(
                tx_id, False,
                blockhash) != self.nodes[2].gettransaction(tx_id)["hex"]
            assert self.nodes[1].getrawtransaction(
                tx_id, False,
                blockhash) == self.nodes[2].gettransaction(tx_id)["hex"]
            assert self.nodes[0].getrawtransaction(
                tx_id, False,
                blockhash) == tx.serialize_without_witness().hex()

        # Coinbase contains the witness commitment nonce, check that RPC shows us
        coinbase_txid = self.nodes[2].getblock(blockhash)['tx'][0]
        coinbase_tx = self.nodes[2].gettransaction(txid=coinbase_txid,
                                                   verbose=True)
        witnesses = coinbase_tx["decoded"]["vin"][0]["txinwitness"]
        assert_equal(len(witnesses), 1)
        assert_is_hex_string(witnesses[0])
        assert_equal(witnesses[0], '00' * 32)

        self.log.info(
            "Verify witness txs without witness data are invalid after the fork"
        )
        self.fail_accept(
            self.nodes[2],
            'non-mandatory-script-verify-flag (Witness program hash mismatch)',
            wit_ids[NODE_2][P2WPKH][2],
            sign=False)
        self.fail_accept(
            self.nodes[2],
            'non-mandatory-script-verify-flag (Witness program was passed an empty witness)',
            wit_ids[NODE_2][P2WSH][2],
            sign=False)
        self.fail_accept(
            self.nodes[2],
            'non-mandatory-script-verify-flag (Witness program hash mismatch)',
            p2sh_ids[NODE_2][P2WPKH][2],
            sign=False,
            redeem_script=witness_script(False, self.pubkey[2]))
        self.fail_accept(
            self.nodes[2],
            'non-mandatory-script-verify-flag (Witness program was passed an empty witness)',
            p2sh_ids[NODE_2][P2WSH][2],
            sign=False,
            redeem_script=witness_script(True, self.pubkey[2]))

        self.log.info("Verify default node can now use witness txs")
        self.success_mine(self.nodes[0], wit_ids[NODE_0][P2WPKH][0],
                          True)  # block 432
        self.success_mine(self.nodes[0], wit_ids[NODE_0][P2WSH][0],
                          True)  # block 433
        self.success_mine(self.nodes[0], p2sh_ids[NODE_0][P2WPKH][0],
                          True)  # block 434
        self.success_mine(self.nodes[0], p2sh_ids[NODE_0][P2WSH][0],
                          True)  # block 435

        self.log.info(
            "Verify sigops are counted in GBT with BIP141 rules after the fork"
        )
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        raw_tx = self.nodes[0].getrawtransaction(txid, True)
        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
        assert_greater_than_or_equal(
            tmpl['sizelimit'], 3999577
        )  # actual maximum size is lower due to minimum mandatory non-witness data
        assert_equal(tmpl['weightlimit'], 4000000)
        assert_equal(tmpl['sigoplimit'], 80000)
        assert_equal(tmpl['transactions'][0]['txid'], txid)
        expected_sigops = 9 if 'txinwitness' in raw_tx["vin"][0] else 8
        assert_equal(tmpl['transactions'][0]['sigops'], expected_sigops)
        assert '!segwit' in tmpl['rules']

        self.generate(self.nodes[0], 1)  # Mine a block to clear the gbt cache

        self.log.info(
            "Non-segwit miners are able to use GBT response after activation.")
        # Create a 3-tx chain: tx1 (non-segwit input, paying to a segwit output) ->
        #                      tx2 (segwit input, paying to a non-segwit output) ->
        #                      tx3 (non-segwit input, paying to a non-segwit output).
        # tx1 is allowed to appear in the block, but no others.
        txid1 = send_to_witness(1, self.nodes[0],
                                find_spendable_utxo(self.nodes[0], 50),
                                self.pubkey[0], False, Decimal("49.996"))
        hex_tx = self.nodes[0].gettransaction(txid)['hex']
        tx = tx_from_hex(hex_tx)
        assert tx.wit.is_null()  # This should not be a segwit input
        assert txid1 in self.nodes[0].getrawmempool()

        tx1_hex = self.nodes[0].gettransaction(txid1)['hex']
        tx1 = tx_from_hex(tx1_hex)

        # Check that hash and wtxid are properly reported in mempool entry (txid1)
        assert_equal(int(self.nodes[0].getmempoolentry(txid1)["hash"], 16),
                     tx1.calc_sha256(True))
        assert_equal(int(self.nodes[0].getmempoolentry(txid1)["wtxid"], 16),
                     tx1.calc_sha256(True))

        # Check that weight and vsize are properly reported in mempool entry (txid1)
        assert_equal(self.nodes[0].getmempoolentry(txid1)["vsize"],
                     tx1.get_vsize())
        assert_equal(self.nodes[0].getmempoolentry(txid1)["weight"],
                     tx1.get_weight())

        # Now create tx2, which will spend from txid1.
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(int(txid1, 16), 0), b''))
        tx.vout.append(
            CTxOut(int(49.99 * COIN),
                   CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
        tx2_hex = self.nodes[0].signrawtransactionwithwallet(
            tx.serialize().hex())['hex']
        txid2 = self.nodes[0].sendrawtransaction(tx2_hex)
        tx = tx_from_hex(tx2_hex)
        assert not tx.wit.is_null()

        # Check that hash and wtxid are properly reported in mempool entry (txid2)
        assert_equal(int(self.nodes[0].getmempoolentry(txid2)["hash"], 16),
                     tx.calc_sha256(True))
        assert_equal(int(self.nodes[0].getmempoolentry(txid2)["wtxid"], 16),
                     tx.calc_sha256(True))

        # Check that weight and vsize are properly reported in mempool entry (txid2)
        assert_equal(self.nodes[0].getmempoolentry(txid2)["vsize"],
                     tx.get_vsize())
        assert_equal(self.nodes[0].getmempoolentry(txid2)["weight"],
                     tx.get_weight())

        # Now create tx3, which will spend from txid2
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(int(txid2, 16), 0), b""))
        tx.vout.append(
            CTxOut(int(49.95 * COIN),
                   CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))  # Huge fee
        tx.calc_sha256()
        txid3 = self.nodes[0].sendrawtransaction(
            hexstring=tx.serialize().hex(), maxfeerate=0)
        assert tx.wit.is_null()
        assert txid3 in self.nodes[0].getrawmempool()

        # Check that getblocktemplate includes all transactions.
        template = self.nodes[0].getblocktemplate({"rules": ["segwit"]})
        template_txids = [t['txid'] for t in template['transactions']]
        assert txid1 in template_txids
        assert txid2 in template_txids
        assert txid3 in template_txids

        # Check that hash and wtxid are properly reported in mempool entry (txid3)
        assert_equal(int(self.nodes[0].getmempoolentry(txid3)["hash"], 16),
                     tx.calc_sha256(True))
        assert_equal(int(self.nodes[0].getmempoolentry(txid3)["wtxid"], 16),
                     tx.calc_sha256(True))

        # Check that weight and vsize are properly reported in mempool entry (txid3)
        assert_equal(self.nodes[0].getmempoolentry(txid3)["vsize"],
                     tx.get_vsize())
        assert_equal(self.nodes[0].getmempoolentry(txid3)["weight"],
                     tx.get_weight())

        # Mine a block to clear the gbt cache again.
        self.generate(self.nodes[0], 1)

        self.log.info("Signing with all-segwit inputs reveals fee rate")
        addr = self.nodes[0].getnewaddress(address_type='p2sh-segwit')
        txid = self.nodes[0].sendtoaddress(addr, 1)
        tx = self.nodes[0].getrawtransaction(txid, True)
        n = -1
        value = -1
        for o in tx["vout"]:
            if o["scriptPubKey"]["address"] == addr:
                n = o["n"]
                value = Decimal(o["value"])
                break
        assert n > -1  # failure means we could not find the address in the outputs despite sending to it
        assert_equal(
            value, 1
        )  # failure means we got an unexpected amount of coins, despite trying to send 1
        fee = Decimal("0.00010000")
        value_out = value - fee
        self.generatetoaddress(self.nodes[0], 1, self.nodes[0].getnewaddress())
        raw = self.nodes[0].createrawtransaction([{
            "txid": txid,
            "vout": n
        }], [{
            self.nodes[0].getnewaddress(): value_out
        }])
        signed = self.nodes[0].signrawtransactionwithwallet(raw)
        assert_equal(signed["complete"], True)
        txsize = self.nodes[0].decoderawtransaction(signed['hex'])['vsize']
        exp_feerate = 1000 * fee / Decimal(txsize)
        assert_approx(signed["feerate"], exp_feerate, Decimal("0.00000010"))
        # discrepancy = 100000000 * (exp_feerate - signed["feerate"])
        # assert -10 < discrepancy < 10
        assert_equal(Decimal(signed["fee"]), fee)

        if not self.options.descriptors:
            self.log.info("Verify behaviour of importaddress and listunspent")

            # Some public keys to be used later
            pubkeys = [
                "0363D44AABD0F1699138239DF2F042C3282C0671CC7A76826A55C8203D90E39242",  # cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb
                "02D3E626B3E616FC8662B489C123349FECBFC611E778E5BE739B257EAE4721E5BF",  # cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97
                "04A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538A62F5BD8EC85C2477F39650BD391EA6250207065B2A81DA8B009FC891E898F0E",  # 91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV
                "02A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538",  # cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd
                "036722F784214129FEB9E8129D626324F3F6716555B603FFE8300BBCB882151228",  # cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66
                "0266A8396EE936BF6D99D17920DB21C6C7B1AB14C639D5CD72B300297E416FD2EC",  # cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K
                "0450A38BD7F0AC212FEBA77354A9B036A32E0F7C81FC4E0C5ADCA7C549C4505D2522458C2D9AE3CEFD684E039194B72C8A10F9CB9D4764AB26FCC2718D421D3B84",  # 92h2XPssjBpsJN5CqSP7v9a7cf2kgDunBC6PDFwJHMACM1rrVBJ
            ]

            # Import a compressed key and an uncompressed key, generate some multisig addresses
            self.nodes[0].importprivkey(
                "92e6XLo5jVAVwrQKPNTs93oQco8f8sDNBcpv73Dsrs397fQtFQn")
            uncompressed_spendable_address = [
                "mvozP4UwyGD2mGZU4D2eMvMLPB9WkMmMQu"
            ]
            self.nodes[0].importprivkey(
                "cNC8eQ5dg3mFAVePDX4ddmPYpPbw41r9bm2jd1nLJT77e6RrzTRR")
            compressed_spendable_address = [
                "mmWQubrDomqpgSYekvsU7HWEVjLFHAakLe"
            ]
            assert not self.nodes[0].getaddressinfo(
                uncompressed_spendable_address[0])['iscompressed']
            assert self.nodes[0].getaddressinfo(
                compressed_spendable_address[0])['iscompressed']

            self.nodes[0].importpubkey(pubkeys[0])
            compressed_solvable_address = [key_to_p2pkh(pubkeys[0])]
            self.nodes[0].importpubkey(pubkeys[1])
            compressed_solvable_address.append(key_to_p2pkh(pubkeys[1]))
            self.nodes[0].importpubkey(pubkeys[2])
            uncompressed_solvable_address = [key_to_p2pkh(pubkeys[2])]

            spendable_anytime = [
            ]  # These outputs should be seen anytime after importprivkey and addmultisigaddress
            spendable_after_importaddress = [
            ]  # These outputs should be seen after importaddress
            solvable_after_importaddress = [
            ]  # These outputs should be seen after importaddress but not spendable
            unsolvable_after_importaddress = [
            ]  # These outputs should be unsolvable after importaddress
            solvable_anytime = [
            ]  # These outputs should be solvable after importpubkey
            unseen_anytime = []  # These outputs should never be seen

            uncompressed_spendable_address.append(
                self.nodes[0].addmultisigaddress(2, [
                    uncompressed_spendable_address[0],
                    compressed_spendable_address[0]
                ])['address'])
            uncompressed_spendable_address.append(
                self.nodes[0].addmultisigaddress(2, [
                    uncompressed_spendable_address[0],
                    uncompressed_spendable_address[0]
                ])['address'])
            compressed_spendable_address.append(
                self.nodes[0].addmultisigaddress(2, [
                    compressed_spendable_address[0],
                    compressed_spendable_address[0]
                ])['address'])
            uncompressed_solvable_address.append(
                self.nodes[0].addmultisigaddress(2, [
                    compressed_spendable_address[0],
                    uncompressed_solvable_address[0]
                ])['address'])
            compressed_solvable_address.append(
                self.nodes[0].addmultisigaddress(2, [
                    compressed_spendable_address[0],
                    compressed_solvable_address[0]
                ])['address'])
            compressed_solvable_address.append(
                self.nodes[0].addmultisigaddress(2, [
                    compressed_solvable_address[0],
                    compressed_solvable_address[1]
                ])['address'])

            # Test multisig_without_privkey
            # We have 2 public keys without private keys, use addmultisigaddress to add to wallet.
            # Money sent to P2SH of multisig of this should only be seen after importaddress with the BASE58 P2SH address.

            multisig_without_privkey_address = self.nodes[
                0].addmultisigaddress(2, [pubkeys[3], pubkeys[4]])['address']
            script = keys_to_multisig_script([pubkeys[3], pubkeys[4]])
            solvable_after_importaddress.append(script_to_p2sh_script(script))

            for i in compressed_spendable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    [bare, p2sh, p2wsh,
                     p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    # p2sh multisig with compressed keys should always be spendable
                    spendable_anytime.extend([p2sh])
                    # bare multisig can be watched and signed, but is not treated as ours
                    solvable_after_importaddress.extend([bare])
                    # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after direct importaddress
                    spendable_after_importaddress.extend([p2wsh, p2sh_p2wsh])
                else:
                    [
                        p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk,
                        p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk,
                        p2sh_p2wsh_p2pkh
                    ] = self.p2pkh_address_to_script(v)
                    # normal P2PKH and P2PK with compressed keys should always be spendable
                    spendable_anytime.extend([p2pkh, p2pk])
                    # P2SH_P2PK, P2SH_P2PKH with compressed keys are spendable after direct importaddress
                    spendable_after_importaddress.extend([
                        p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh,
                        p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                    ])
                    # P2WPKH and P2SH_P2WPKH with compressed keys should always be spendable
                    spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])

            for i in uncompressed_spendable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    [bare, p2sh, p2wsh,
                     p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    # p2sh multisig with uncompressed keys should always be spendable
                    spendable_anytime.extend([p2sh])
                    # bare multisig can be watched and signed, but is not treated as ours
                    solvable_after_importaddress.extend([bare])
                    # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
                    unseen_anytime.extend([p2wsh, p2sh_p2wsh])
                else:
                    [
                        p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk,
                        p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk,
                        p2sh_p2wsh_p2pkh
                    ] = self.p2pkh_address_to_script(v)
                    # normal P2PKH and P2PK with uncompressed keys should always be spendable
                    spendable_anytime.extend([p2pkh, p2pk])
                    # P2SH_P2PK and P2SH_P2PKH are spendable after direct importaddress
                    spendable_after_importaddress.extend(
                        [p2sh_p2pk, p2sh_p2pkh])
                    # Witness output types with uncompressed keys are never seen
                    unseen_anytime.extend([
                        p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh,
                        p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                    ])

            for i in compressed_solvable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    # Multisig without private is not seen after addmultisigaddress, but seen after importaddress
                    [bare, p2sh, p2wsh,
                     p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    solvable_after_importaddress.extend(
                        [bare, p2sh, p2wsh, p2sh_p2wsh])
                else:
                    [
                        p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk,
                        p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk,
                        p2sh_p2wsh_p2pkh
                    ] = self.p2pkh_address_to_script(v)
                    # normal P2PKH, P2PK, P2WPKH and P2SH_P2WPKH with compressed keys should always be seen
                    solvable_anytime.extend([p2pkh, p2pk, p2wpkh, p2sh_p2wpkh])
                    # P2SH_P2PK, P2SH_P2PKH with compressed keys are seen after direct importaddress
                    solvable_after_importaddress.extend([
                        p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh,
                        p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                    ])

            for i in uncompressed_solvable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    [bare, p2sh, p2wsh,
                     p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    # Base uncompressed multisig without private is not seen after addmultisigaddress, but seen after importaddress
                    solvable_after_importaddress.extend([bare, p2sh])
                    # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
                    unseen_anytime.extend([p2wsh, p2sh_p2wsh])
                else:
                    [
                        p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk,
                        p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk,
                        p2sh_p2wsh_p2pkh
                    ] = self.p2pkh_address_to_script(v)
                    # normal P2PKH and P2PK with uncompressed keys should always be seen
                    solvable_anytime.extend([p2pkh, p2pk])
                    # P2SH_P2PK, P2SH_P2PKH with uncompressed keys are seen after direct importaddress
                    solvable_after_importaddress.extend(
                        [p2sh_p2pk, p2sh_p2pkh])
                    # Witness output types with uncompressed keys are never seen
                    unseen_anytime.extend([
                        p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh,
                        p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                    ])

            op1 = CScript([OP_1])
            op0 = CScript([OP_0])
            # 2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe is the P2SH(P2PKH) version of mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V
            unsolvable_address_key = bytes.fromhex(
                "02341AEC7587A51CDE5279E0630A531AEA2615A9F80B17E8D9376327BAEAA59E3D"
            )
            unsolvablep2pkh = key_to_p2pkh_script(unsolvable_address_key)
            unsolvablep2wshp2pkh = script_to_p2wsh_script(unsolvablep2pkh)
            p2shop0 = script_to_p2sh_script(op0)
            p2wshop1 = script_to_p2wsh_script(op1)
            unsolvable_after_importaddress.append(unsolvablep2pkh)
            unsolvable_after_importaddress.append(unsolvablep2wshp2pkh)
            unsolvable_after_importaddress.append(
                op1)  # OP_1 will be imported as script
            unsolvable_after_importaddress.append(p2wshop1)
            unseen_anytime.append(
                op0
            )  # OP_0 will be imported as P2SH address with no script provided
            unsolvable_after_importaddress.append(p2shop0)

            spendable_txid = []
            solvable_txid = []
            spendable_txid.append(
                self.mine_and_test_listunspent(spendable_anytime, 2))
            solvable_txid.append(
                self.mine_and_test_listunspent(solvable_anytime, 1))
            self.mine_and_test_listunspent(
                spendable_after_importaddress + solvable_after_importaddress +
                unseen_anytime + unsolvable_after_importaddress, 0)

            importlist = []
            for i in compressed_spendable_address + uncompressed_spendable_address + compressed_solvable_address + uncompressed_solvable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    bare = bytes.fromhex(v['hex'])
                    importlist.append(bare.hex())
                    importlist.append(script_to_p2wsh_script(bare).hex())
                else:
                    pubkey = bytes.fromhex(v['pubkey'])
                    p2pk = key_to_p2pk_script(pubkey)
                    p2pkh = key_to_p2pkh_script(pubkey)
                    importlist.append(p2pk.hex())
                    importlist.append(p2pkh.hex())
                    importlist.append(key_to_p2wpkh_script(pubkey).hex())
                    importlist.append(script_to_p2wsh_script(p2pk).hex())
                    importlist.append(script_to_p2wsh_script(p2pkh).hex())

            importlist.append(unsolvablep2pkh.hex())
            importlist.append(unsolvablep2wshp2pkh.hex())
            importlist.append(op1.hex())
            importlist.append(p2wshop1.hex())

            for i in importlist:
                # import all generated addresses. The wallet already has the private keys for some of these, so catch JSON RPC
                # exceptions and continue.
                try_rpc(
                    -4,
                    "The wallet already contains the private key for this address or script",
                    self.nodes[0].importaddress, i, "", False, True)

            self.nodes[0].importaddress(
                script_to_p2sh(op0))  # import OP_0 as address only
            self.nodes[0].importaddress(multisig_without_privkey_address
                                        )  # Test multisig_without_privkey

            spendable_txid.append(
                self.mine_and_test_listunspent(
                    spendable_anytime + spendable_after_importaddress, 2))
            solvable_txid.append(
                self.mine_and_test_listunspent(
                    solvable_anytime + solvable_after_importaddress, 1))
            self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
            self.mine_and_test_listunspent(unseen_anytime, 0)

            spendable_txid.append(
                self.mine_and_test_listunspent(
                    spendable_anytime + spendable_after_importaddress, 2))
            solvable_txid.append(
                self.mine_and_test_listunspent(
                    solvable_anytime + solvable_after_importaddress, 1))
            self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
            self.mine_and_test_listunspent(unseen_anytime, 0)

            # Repeat some tests. This time we don't add witness scripts with importaddress
            # Import a compressed key and an uncompressed key, generate some multisig addresses
            self.nodes[0].importprivkey(
                "927pw6RW8ZekycnXqBQ2JS5nPyo1yRfGNN8oq74HeddWSpafDJH")
            uncompressed_spendable_address = [
                "mguN2vNSCEUh6rJaXoAVwY3YZwZvEmf5xi"
            ]
            self.nodes[0].importprivkey(
                "cMcrXaaUC48ZKpcyydfFo8PxHAjpsYLhdsp6nmtB3E2ER9UUHWnw")
            compressed_spendable_address = [
                "n1UNmpmbVUJ9ytXYXiurmGPQ3TRrXqPWKL"
            ]

            self.nodes[0].importpubkey(pubkeys[5])
            compressed_solvable_address = [key_to_p2pkh(pubkeys[5])]
            self.nodes[0].importpubkey(pubkeys[6])
            uncompressed_solvable_address = [key_to_p2pkh(pubkeys[6])]

            unseen_anytime = []  # These outputs should never be seen
            solvable_anytime = [
            ]  # These outputs should be solvable after importpubkey
            unseen_anytime = []  # These outputs should never be seen

            uncompressed_spendable_address.append(
                self.nodes[0].addmultisigaddress(2, [
                    uncompressed_spendable_address[0],
                    compressed_spendable_address[0]
                ])['address'])
            uncompressed_spendable_address.append(
                self.nodes[0].addmultisigaddress(2, [
                    uncompressed_spendable_address[0],
                    uncompressed_spendable_address[0]
                ])['address'])
            compressed_spendable_address.append(
                self.nodes[0].addmultisigaddress(2, [
                    compressed_spendable_address[0],
                    compressed_spendable_address[0]
                ])['address'])
            uncompressed_solvable_address.append(
                self.nodes[0].addmultisigaddress(2, [
                    compressed_solvable_address[0],
                    uncompressed_solvable_address[0]
                ])['address'])
            compressed_solvable_address.append(
                self.nodes[0].addmultisigaddress(2, [
                    compressed_spendable_address[0],
                    compressed_solvable_address[0]
                ])['address'])

            premature_witaddress = []

            for i in compressed_spendable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    [bare, p2sh, p2wsh,
                     p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    premature_witaddress.append(script_to_p2sh(p2wsh))
                else:
                    [
                        p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk,
                        p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk,
                        p2sh_p2wsh_p2pkh
                    ] = self.p2pkh_address_to_script(v)
                    # P2WPKH, P2SH_P2WPKH are always spendable
                    spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])

            for i in uncompressed_spendable_address + uncompressed_solvable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    [bare, p2sh, p2wsh,
                     p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
                    unseen_anytime.extend([p2wsh, p2sh_p2wsh])
                else:
                    [
                        p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk,
                        p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk,
                        p2sh_p2wsh_p2pkh
                    ] = self.p2pkh_address_to_script(v)
                    # P2WPKH, P2SH_P2WPKH with uncompressed keys are never seen
                    unseen_anytime.extend([p2wpkh, p2sh_p2wpkh])

            for i in compressed_solvable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    [bare, p2sh, p2wsh,
                     p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    premature_witaddress.append(script_to_p2sh(p2wsh))
                else:
                    [
                        p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk,
                        p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk,
                        p2sh_p2wsh_p2pkh
                    ] = self.p2pkh_address_to_script(v)
                    # P2SH_P2PK, P2SH_P2PKH with compressed keys are always solvable
                    solvable_anytime.extend([p2wpkh, p2sh_p2wpkh])

            self.mine_and_test_listunspent(spendable_anytime, 2)
            self.mine_and_test_listunspent(solvable_anytime, 1)
            self.mine_and_test_listunspent(unseen_anytime, 0)

            # Check that createrawtransaction/decoderawtransaction with non-v0 Bech32 works
            v1_addr = program_to_witness(1, [3, 5])
            v1_tx = self.nodes[0].createrawtransaction(
                [getutxo(spendable_txid[0])], {v1_addr: 1})
            v1_decoded = self.nodes[1].decoderawtransaction(v1_tx)
            assert_equal(v1_decoded['vout'][0]['scriptPubKey']['address'],
                         v1_addr)
            assert_equal(v1_decoded['vout'][0]['scriptPubKey']['hex'],
                         "51020305")

            # Check that spendable outputs are really spendable
            self.create_and_mine_tx_from_txids(spendable_txid)

            # import all the private keys so solvable addresses become spendable
            self.nodes[0].importprivkey(
                "cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb")
            self.nodes[0].importprivkey(
                "cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97")
            self.nodes[0].importprivkey(
                "91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV")
            self.nodes[0].importprivkey(
                "cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd")
            self.nodes[0].importprivkey(
                "cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66")
            self.nodes[0].importprivkey(
                "cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K")
            self.create_and_mine_tx_from_txids(solvable_txid)

            # Test that importing native P2WPKH/P2WSH scripts works
            for use_p2wsh in [False, True]:
                if use_p2wsh:
                    scriptPubKey = "00203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a"
                    transaction = "01000000000100e1f505000000002200203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a00000000"
                else:
                    scriptPubKey = "a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d87"
                    transaction = "01000000000100e1f5050000000017a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d8700000000"

                self.nodes[1].importaddress(scriptPubKey, "", False)
                rawtxfund = self.nodes[1].fundrawtransaction(
                    transaction)['hex']
                rawtxfund = self.nodes[1].signrawtransactionwithwallet(
                    rawtxfund)["hex"]
                txid = self.nodes[1].sendrawtransaction(rawtxfund)

                assert_equal(self.nodes[1].gettransaction(txid, True)["txid"],
                             txid)
                assert_equal(
                    self.nodes[1].listtransactions("*", 1, 0, True)[0]["txid"],
                    txid)

                # Assert it is properly saved
                self.restart_node(1)
                assert_equal(self.nodes[1].gettransaction(txid, True)["txid"],
                             txid)
                assert_equal(
                    self.nodes[1].listtransactions("*", 1, 0, True)[0]["txid"],
                    txid)
    def run_test(self):

        print("Testing wallet secret recovery")
        self.test_wallet_recovery()

        print("General Confidential tests")
        # Running balances
        node0 = self.nodes[0].getbalance()["bitcoin"]
        assert_equal(node0, 21000000) # just making sure initialfreecoins is working
        node1 = 0
        node2 = 0

        self.nodes[0].generate(101)
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), node0, "", "", True)
        self.nodes[0].generate(101)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, "bitcoin"), node1)
        assert_equal(self.nodes[2].getbalance("*", 1, False, "bitcoin"), node2)

        # Send 3 BTC from 0 to a new unconfidential address of 2 with
        # the sendtoaddress call
        address = self.nodes[2].getnewaddress()
        unconfidential_address = self.nodes[2].validateaddress(address)["unconfidential"]
        value0 = 3
        self.nodes[0].sendtoaddress(unconfidential_address, value0)
        self.nodes[0].generate(101)
        self.sync_all()

        node0 = node0 - value0
        node2 = node2 + value0

        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, "bitcoin"), node1)
        assert_equal(self.nodes[2].getbalance()["bitcoin"], node2)

        # Send 5 BTC from 0 to a new address of 2 with the sendtoaddress call
        address2 = self.nodes[2].getnewaddress()
        unconfidential_address2 = self.nodes[2].validateaddress(address2)["unconfidential"]
        value1 = 5
        confidential_tx_id = self.nodes[0].sendtoaddress(address2, value1)
        self.nodes[0].generate(101)
        self.sync_all()

        node0 = node0 - value1
        node2 = node2 + value1

        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, "bitcoin"), node1)
        assert_equal(self.nodes[2].getbalance()["bitcoin"], node2)

        # Send 7 BTC from 0 to the unconfidential address of 2 and 11 BTC to the
        # confidential address using the raw transaction interface
        change_address = self.nodes[0].getnewaddress()
        value2 = 7
        value3 = 11
        value23 = value2 + value3
        unspent = self.nodes[0].listunspent(1, 9999999, [], True, {"asset": "bitcoin"})
        unspent = [i for i in unspent if i['amount'] > value23]
        assert_equal(len(unspent), 1)
        fee = Decimal('0.0001')
        tx = self.nodes[0].createrawtransaction([{"txid": unspent[0]["txid"],
                                                  "vout": unspent[0]["vout"],
                                                  "nValue": unspent[0]["amount"]}],
                                                {unconfidential_address: value2, address2: value3,
                                                change_address: unspent[0]["amount"] - value2 - value3 - fee, "fee":fee})
        tx = self.nodes[0].blindrawtransaction(tx)
        tx_signed = self.nodes[0].signrawtransactionwithwallet(tx)
        raw_tx_id = self.nodes[0].sendrawtransaction(tx_signed['hex'])
        self.nodes[0].generate(101)
        self.sync_all()

        node0 -= (value2 + value3)
        node2 += value2 + value3

        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, "bitcoin"), node1)
        assert_equal(self.nodes[2].getbalance()["bitcoin"], node2)

        # Check 2's listreceivedbyaddress
        received_by_address = self.nodes[2].listreceivedbyaddress(0, False, False, "", "bitcoin")
        validate_by_address = [(address2, {"bitcoin": value1 + value3}), (address, {"bitcoin": value0 + value2})]
        assert_equal(sorted([(ele['address'], ele['amount']) for ele in received_by_address], key=lambda t: t[0]),
                sorted(validate_by_address, key = lambda t: t[0]))

        # Give an auditor (node 1) a blinding key to allow her to look at
        # transaction values
        self.nodes[1].importaddress(address2)
        received_by_address = self.nodes[1].listreceivedbyaddress(1, False, True)
        #Node sees nothing unless it understands the values
        assert_equal(len(received_by_address), 0)
        assert_equal(len(self.nodes[1].listunspent(1, 9999999, [], True, {"asset": "bitcoin"})), 0)

        # Import the blinding key
        blindingkey = self.nodes[2].dumpblindingkey(address2)
        self.nodes[1].importblindingkey(address2, blindingkey)
        # Check the auditor's gettransaction and listreceivedbyaddress
        # Needs rescan to update wallet txns
        conf_tx = self.nodes[1].gettransaction(confidential_tx_id, True)
        assert_equal(conf_tx['amount']["bitcoin"], value1)

        # Make sure wallet can now deblind part of transaction
        deblinded_tx = self.nodes[1].unblindrawtransaction(conf_tx['hex'])['hex']
        for output in self.nodes[1].decoderawtransaction(deblinded_tx)["vout"]:
            if "value" in output and output["scriptPubKey"]["type"] != "fee":
                assert_equal(output["scriptPubKey"]["addresses"][0], self.nodes[1].validateaddress(address2)['unconfidential'])
                found_unblinded = True
        assert(found_unblinded)

        assert_equal(self.nodes[1].gettransaction(raw_tx_id, True)['amount']["bitcoin"], value3)
        list_unspent = self.nodes[1].listunspent(1, 9999999, [], True, {"asset": "bitcoin"})
        assert_equal(list_unspent[0]['amount']+list_unspent[1]['amount'], value1+value3)
        received_by_address = self.nodes[1].listreceivedbyaddress(1, False, True)
        assert_equal(len(received_by_address), 1)
        assert_equal((received_by_address[0]['address'], received_by_address[0]['amount']['bitcoin']),
                     (unconfidential_address2, value1 + value3))

        # Spending a single confidential output and sending it to a
        # unconfidential output is not possible with CT. Test the
        # correct behavior of blindrawtransaction.
        unspent = self.nodes[0].listunspent(1, 9999999, [], True, {"asset": "bitcoin"})
        unspent = [i for i in unspent if i['amount'] > value23]
        assert_equal(len(unspent), 1)
        tx = self.nodes[0].createrawtransaction([{"txid": unspent[0]["txid"],
                                                  "vout": unspent[0]["vout"],
                                                  "nValue": unspent[0]["amount"]}],
                                                  {unconfidential_address: unspent[0]["amount"] - fee, "fee":fee})

        # Test that blindrawtransaction adds an OP_RETURN output to balance blinders
        temptx = self.nodes[0].blindrawtransaction(tx)
        decodedtx = self.nodes[0].decoderawtransaction(temptx)
        assert_equal(decodedtx["vout"][-1]["scriptPubKey"]["asm"], "OP_RETURN")
        assert_equal(len(decodedtx["vout"]), 3)

        # Create same transaction but with a change/dummy output.
        # It should pass the blinding step.
        value4 = 17
        change_address = self.nodes[0].getrawchangeaddress()
        tx = self.nodes[0].createrawtransaction([{"txid": unspent[0]["txid"],
                                                  "vout": unspent[0]["vout"],
                                                  "nValue": unspent[0]["amount"]}],
                                                  {unconfidential_address: value4,
                                                   change_address: unspent[0]["amount"] - value4 - fee, "fee":fee})
        tx = self.nodes[0].blindrawtransaction(tx)
        tx_signed = self.nodes[0].signrawtransactionwithwallet(tx)
        txid = self.nodes[0].sendrawtransaction(tx_signed['hex'])
        decodedtx = self.nodes[0].decoderawtransaction(tx_signed["hex"])
        self.nodes[0].generate(101)
        self.sync_all()

        unblindfound = False
        for i in range(len(decodedtx["vout"])):
            txout = self.nodes[0].gettxout(txid, i)
            if txout is not None and "asset" in txout:
                unblindfound = True

        if unblindfound == False:
            raise Exception("No unconfidential output detected when one should exist")

        node0 -= value4
        node2 += value4
        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, "bitcoin"), node1)
        assert_equal(self.nodes[2].getbalance()["bitcoin"], node2)

        # Testing wallet's ability to deblind its own outputs
        addr = self.nodes[0].getnewaddress()
        addr2 = self.nodes[0].getnewaddress()
        # We add two to-blind outputs, fundraw adds an already-blinded change output
        # If we only add one, the newly blinded will be 0-blinded because input = -output
        raw = self.nodes[0].createrawtransaction([], {addr:Decimal('1.1'), addr2:1})
        funded = self.nodes[0].fundrawtransaction(raw)
        # fund again to make sure no blinded outputs were created (would fail)
        funded = self.nodes[0].fundrawtransaction(funded["hex"])
        blinded = self.nodes[0].blindrawtransaction(funded["hex"])
        # blind again to make sure we know output blinders
        blinded2 = self.nodes[0].blindrawtransaction(blinded)
        # then sign and send
        signed = self.nodes[0].signrawtransactionwithwallet(blinded2)
        self.nodes[0].sendrawtransaction(signed["hex"])

        # Aside: Check all outputs after fundraw are properly marked for blinding
        fund_decode = self.nodes[0].decoderawtransaction(funded["hex"])
        for output in fund_decode["vout"][:-1]:
            assert "asset" in output
            assert "value" in output
            assert output["scriptPubKey"]["type"] != "fee"
            assert output["commitmentnonce_fully_valid"]
        assert fund_decode["vout"][-1]["scriptPubKey"]["type"] == "fee"
        assert not fund_decode["vout"][-1]["commitmentnonce_fully_valid"]

        # Also check that all fundraw outputs marked for blinding are blinded later
        for blind_tx in [blinded, blinded2]:
            blind_decode = self.nodes[0].decoderawtransaction(blind_tx)
            for output in blind_decode["vout"][:-1]:
                assert "asset" not in output
                assert "value" not in output
                assert output["scriptPubKey"]["type"] != "fee"
                assert output["commitmentnonce_fully_valid"]
            assert blind_decode["vout"][-1]["scriptPubKey"]["type"] == "fee"
            assert "asset" in blind_decode["vout"][-1]
            assert "value" in blind_decode["vout"][-1]
            assert not blind_decode["vout"][-1]["commitmentnonce_fully_valid"]

        # Check createblindedaddress functionality
        blinded_addr = self.nodes[0].getnewaddress()
        validated_addr = self.nodes[0].validateaddress(blinded_addr)
        blinding_pubkey = self.nodes[0].validateaddress(blinded_addr)["confidential_key"]
        blinding_key = self.nodes[0].dumpblindingkey(blinded_addr)
        assert_equal(blinded_addr, self.nodes[1].createblindedaddress(validated_addr["unconfidential"], blinding_pubkey))

        # If a blinding key is over-ridden by a newly imported one, funds may be unaccounted for
        new_addr = self.nodes[0].getnewaddress()
        new_validated = self.nodes[0].validateaddress(new_addr)
        self.nodes[2].sendtoaddress(new_addr, 1)
        self.sync_all()
        diff_blind = self.nodes[1].createblindedaddress(new_validated["unconfidential"], blinding_pubkey)
        assert_equal(len(self.nodes[0].listunspent(0, 0, [new_validated["unconfidential"]])), 1)
        self.nodes[0].importblindingkey(diff_blind, blinding_key)
        # CT values for this wallet transaction  have been cached via importblindingkey
        # therefore result will be same even though we change blinding keys
        assert_equal(len(self.nodes[0].listunspent(0, 0, [new_validated["unconfidential"]])), 1)

        # Confidential Assets Tests

        print("Assets tests...")

        # Bitcoin is the first issuance
        assert_equal(self.nodes[0].listissuances()[0]["assetlabel"], "bitcoin")
        assert_equal(len(self.nodes[0].listissuances()), 1)

        # Unblinded issuance of asset
        issued = self.nodes[0].issueasset(1, 1, False)
        self.nodes[0].reissueasset(issued["asset"], 1)

        # Compare resulting fields with getrawtransaction
        raw_details = self.nodes[0].getrawtransaction(issued["txid"], 1)
        assert_equal(issued["entropy"], raw_details["vin"][issued["vin"]]["issuance"]["assetEntropy"])
        assert_equal(issued["asset"], raw_details["vin"][issued["vin"]]["issuance"]["asset"])
        assert_equal(issued["token"], raw_details["vin"][issued["vin"]]["issuance"]["token"])

        self.nodes[0].generate(1)
        self.sync_all()

        issued2 = self.nodes[0].issueasset(2, 1)
        test_asset = issued2["asset"]
        assert_equal(self.nodes[0].getwalletinfo()['balance'][test_asset], Decimal(2))
        assert(test_asset not in self.nodes[1].getwalletinfo()['balance'])

        # Assets balance checking, note that accounts are completely ignored because
        # balance queries with accounts are horrifically broken upstream
        assert_equal(self.nodes[0].getbalance("*", 0, False, "bitcoin"), self.nodes[0].getbalance("*", 0, False, "bitcoin"))
        assert_equal(self.nodes[0].getwalletinfo()['balance']['bitcoin'], self.nodes[0].getbalance("*", 0, False, "bitcoin"))

        # Send some bitcoin and other assets over as well to fund wallet
        addr = self.nodes[2].getnewaddress()
        self.nodes[0].sendtoaddress(addr, 5)
        self.nodes[0].sendmany("", {addr: 1, self.nodes[2].getnewaddress(): 13}, 0, "", [], False, 1, "UNSET", {addr: test_asset})

        self.sync_all()

        # Should have exactly 1 in change(trusted, though not confirmed) after sending one off
        assert_equal(self.nodes[0].getbalance("*", 0, False, test_asset), 1)
        assert_equal(self.nodes[2].getunconfirmedbalance()[test_asset], Decimal(1))

        b_utxos = self.nodes[2].listunspent(0, 0, [], True, {"asset": "bitcoin"})
        t_utxos = self.nodes[2].listunspent(0, 0, [], True, {"asset": test_asset})

        assert_equal(len(self.nodes[2].listunspent(0, 0, [])), len(b_utxos)+len(t_utxos))

        # Now craft a blinded transaction via raw api
        rawaddrs = []
        for i in range(2):
            rawaddrs.append(self.nodes[1].getnewaddress())
        raw_assets = self.nodes[2].createrawtransaction([{"txid":b_utxos[0]['txid'], "vout":b_utxos[0]['vout'], "nValue":b_utxos[0]['amount']}, {"txid":b_utxos[1]['txid'], "vout":b_utxos[1]['vout'], "nValue":b_utxos[1]['amount'], "asset":b_utxos[1]['asset']}, {"txid":t_utxos[0]['txid'], "vout":t_utxos[0]['vout'], "nValue":t_utxos[0]['amount'], "asset":t_utxos[0]['asset']}], {rawaddrs[1]:Decimal(t_utxos[0]['amount']), rawaddrs[0]:Decimal(b_utxos[0]['amount']+b_utxos[1]['amount']-Decimal("0.01")), "fee":Decimal("0.01")}, 0, False, {rawaddrs[0]:b_utxos[0]['asset'], rawaddrs[1]:t_utxos[0]['asset'], "fee":b_utxos[0]['asset']})

        # Sign unblinded, then blinded
        signed_assets = self.nodes[2].signrawtransactionwithwallet(raw_assets)
        blind_assets = self.nodes[2].blindrawtransaction(raw_assets)
        signed_assets = self.nodes[2].signrawtransactionwithwallet(blind_assets)

        # And finally send
        self.nodes[2].sendrawtransaction(signed_assets['hex'])
        self.nodes[2].generate(101)
        self.sync_all()

        issuancedata = self.nodes[2].issueasset(0, Decimal('0.00000006')) #0 of asset, 6 reissuance token

        # Node 2 will send node 1 a reissuance token, both will generate assets
        self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), Decimal('0.00000001'), "", "", False, False, 1, "UNSET", issuancedata["token"])
        # node 1 needs to know about a (re)issuance to reissue itself
        self.nodes[1].importaddress(self.nodes[2].gettransaction(issuancedata["txid"])["details"][0]["address"])
        # also send some bitcoin
        self.nodes[2].generate(1)
        self.sync_all()

        self.nodes[1].reissueasset(issuancedata["asset"], Decimal('0.05'))
        self.nodes[2].reissueasset(issuancedata["asset"], Decimal('0.025'))
        self.nodes[1].generate(1)
        self.sync_all()

        # Check for value accounting when asset issuance is null but token not, ie unblinded
        # HACK: Self-send to sweep up bitcoin inputs into blinded output.
        # We were hitting https://github.com/ElementsProject/elements/issues/473 for the following issuance
        self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[0].getwalletinfo()["balance"]["bitcoin"], "", "", True)
        issued = self.nodes[0].issueasset(0, 1, False)
        walletinfo = self.nodes[0].getwalletinfo()
        assert(issued["asset"] not in walletinfo["balance"])
        assert_equal(walletinfo["balance"][issued["token"]], Decimal(1))
        assert(issued["asset"] not in walletinfo["unconfirmed_balance"])
        assert(issued["token"] not in walletinfo["unconfirmed_balance"])

        # Check for value when receiving different assets by same address.
        self.nodes[0].sendtoaddress(unconfidential_address2, Decimal('0.00000001'), "", "", False, False, 1, "UNSET", test_asset)
        self.nodes[0].sendtoaddress(unconfidential_address2, Decimal('0.00000002'), "", "", False, False, 1, "UNSET", test_asset)
        self.nodes[0].generate(1)
        self.sync_all()
        received_by_address = self.nodes[1].listreceivedbyaddress(0, False, True)
        multi_asset_amount = [x for x in received_by_address if x['address'] == unconfidential_address2][0]['amount']
        assert_equal(multi_asset_amount['bitcoin'], value1 + value3)
        assert_equal(multi_asset_amount[test_asset], Decimal('0.00000003'))

        # Check blinded multisig functionality and partial blinding functionality

        # Get two pubkeys
        blinded_addr = self.nodes[0].getnewaddress()
        pubkey = self.nodes[0].getaddressinfo(blinded_addr)["pubkey"]
        blinded_addr2 = self.nodes[1].getnewaddress()
        pubkey2 = self.nodes[1].getaddressinfo(blinded_addr2)["pubkey"]
        pubkeys = [pubkey, pubkey2]
        # Add multisig address
        unconfidential_addr = self.nodes[0].addmultisigaddress(2, pubkeys)["address"]
        self.nodes[1].addmultisigaddress(2, pubkeys)
        self.nodes[0].importaddress(unconfidential_addr)
        self.nodes[1].importaddress(unconfidential_addr)
        # Use blinding key from node 0's original getnewaddress call
        blinding_pubkey = self.nodes[0].getaddressinfo(blinded_addr)["confidential_key"]
        blinding_key = self.nodes[0].dumpblindingkey(blinded_addr)
        # Create blinded address from p2sh address and import corresponding privkey
        blinded_multisig_addr = self.nodes[0].createblindedaddress(unconfidential_addr, blinding_pubkey)
        self.nodes[0].importblindingkey(blinded_multisig_addr, blinding_key)

        # Issue new asset, to use different assets in one transaction when doing
        # partial blinding. Just to make these tests a bit more elaborate :-)
        issued3 = self.nodes[2].issueasset(1, 0)
        self.nodes[2].generate(1)
        self.sync_all()
        node2_balance = self.nodes[2].getbalance()
        assert(issued3['asset'] in node2_balance)
        assert_equal(node2_balance[issued3['asset']], Decimal(1))

        # Send asset to blinded multisig address and check that it was received
        self.nodes[2].sendtoaddress(address=blinded_multisig_addr, amount=1, assetlabel=issued3['asset'])
        self.sync_all()
        # We will use this multisig UTXO in our partially-blinded transaction,
        # and will also check that multisig UTXO can be successfully spent
        # after the transaction is signed by node1 and node0 in succession.
        unspent_asset = self.nodes[0].listunspent(0, 0, [unconfidential_addr], True, {"asset":issued3['asset']})
        assert_equal(len(unspent_asset), 1)
        assert(issued3['asset'] not in self.nodes[2].getbalance())

        # Create new UTXO on node0 to be used in our partially-blinded transaction
        blinded_addr = self.nodes[0].getnewaddress()
        addr = self.nodes[0].validateaddress(blinded_addr)["unconfidential"]
        self.nodes[0].sendtoaddress(blinded_addr, 0.1)
        unspent = self.nodes[0].listunspent(0, 0, [addr])
        assert_equal(len(unspent), 1)

        # Create new UTXO on node1 to be used in our partially-blinded transaction
        blinded_addr2 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[1].validateaddress(blinded_addr2)["unconfidential"]
        self.nodes[1].sendtoaddress(blinded_addr2, 0.11)
        unspent2 = self.nodes[1].listunspent(0, 0, [addr2])
        assert_equal(len(unspent2), 1)

        # The transaction will have three non-fee outputs
        dst_addr = self.nodes[0].getnewaddress()
        dst_addr2 = self.nodes[1].getnewaddress()
        dst_addr3 = self.nodes[2].getnewaddress()

        # Inputs are selected up front
        inputs = [{"txid": unspent2[0]["txid"], "vout": unspent2[0]["vout"]}, {"txid": unspent[0]["txid"], "vout": unspent[0]["vout"]}, {"txid": unspent_asset[0]["txid"], "vout": unspent_asset[0]["vout"]}]

        # Create one part of the transaction to partially blind
        rawtx = self.nodes[0].createrawtransaction(
            inputs, {dst_addr2: Decimal("0.01")})

        # Create another part of the transaction to partially blind
        rawtx2 = self.nodes[0].createrawtransaction(
            inputs,
            {dst_addr: Decimal("0.1"), dst_addr3: Decimal("1.0")},
            0,
            False,
            {dst_addr: unspent[0]['asset'], dst_addr3: unspent_asset[0]['asset']})

        sum_i = unspent2[0]["amount"] + unspent[0]["amount"]
        sum_o = 0.01 + 0.10 + 0.1
        assert_equal(int(round(sum_i*COIN)), int(round(sum_o*COIN)))

        # Blind the first part of the transaction - we need to supply the
        # assetcommmitments for all of the inputs, for the surjectionproof
        # to be valid after we combine the transactions
        blindtx = self.nodes[1].blindrawtransaction(
            rawtx, True, [
                unspent2[0]['assetcommitment'],
                unspent[0]['assetcommitment'],
                unspent_asset[0]['assetcommitment']
            ])

        # Combine the transactions

        # Blinded, but incomplete transaction.
        # 3 inputs and 1 output, but no fee output, and
        # it was blinded with 3 asset commitments, that means
        # the final transaction should have 3 inputs.
        btx = CTransaction()
        btx.deserialize(io.BytesIO(hex_str_to_bytes(blindtx)))

        # Unblinded transaction, with 3 inputs and 2 outputs.
        # We will add them to the other transaction to make it complete.
        ubtx = CTransaction()
        ubtx.deserialize(io.BytesIO(hex_str_to_bytes(rawtx2)))

        # We will add outputs of unblinded transaction
        # on top of inputs and outputs of the blinded, but incomplete transaction.
        # We also append empty witness instances to make witness arrays match
        # vin/vout arrays
        btx.wit.vtxinwit.append(CTxInWitness())
        btx.vout.append(ubtx.vout[0])
        btx.wit.vtxoutwit.append(CTxOutWitness())
        btx.wit.vtxinwit.append(CTxInWitness())
        btx.vout.append(ubtx.vout[1])
        btx.wit.vtxoutwit.append(CTxOutWitness())
        # Add explicit fee output
        btx.vout.append(CTxOut(nValue=CTxOutValue(10000000),
                               nAsset=CTxOutAsset(BITCOIN_ASSET_OUT)))
        btx.wit.vtxoutwit.append(CTxOutWitness())

        # Input 0 is bitcoin asset (already blinded)
        # Input 1 is also bitcoin asset
        # Input 2 is our new asset

        # Blind with wrong order of assetcommitments - such transaction should be rejected
        blindtx = self.nodes[0].blindrawtransaction(
            bytes_to_hex_str(btx.serialize()), True, [
                unspent_asset[0]['assetcommitment'],
                unspent[0]['assetcommitment'],
                unspent2[0]['assetcommitment']
            ])

        stx2 = self.nodes[1].signrawtransactionwithwallet(blindtx)
        stx = self.nodes[0].signrawtransactionwithwallet(stx2['hex'])
        self.sync_all()

        assert_raises_rpc_error(-26, "bad-txns-in-ne-out", self.nodes[2].sendrawtransaction, stx['hex'])

        # Blind with correct order of assetcommitments
        blindtx = self.nodes[0].blindrawtransaction(
            bytes_to_hex_str(btx.serialize()), True, [
                unspent2[0]['assetcommitment'],
                unspent[0]['assetcommitment'],
                unspent_asset[0]['assetcommitment']
            ])

        stx2 = self.nodes[1].signrawtransactionwithwallet(blindtx)
        stx = self.nodes[0].signrawtransactionwithwallet(stx2['hex'])
        txid = self.nodes[2].sendrawtransaction(stx['hex'])
        self.nodes[2].generate(1)
        assert self.nodes[2].getrawtransaction(txid, 1)['confirmations'] == 1
        self.sync_all()

        # Check that the sent asset has reached its destination
        unconfidential_dst_addr3 = self.nodes[2].validateaddress(dst_addr3)["unconfidential"]
        unspent_asset2 = self.nodes[2].listunspent(1, 1, [unconfidential_dst_addr3], True, {"asset":issued3['asset']})
        assert_equal(len(unspent_asset2), 1)
        assert_equal(unspent_asset2[0]['amount'], Decimal(1))
        # And that the balance was correctly updated
        assert_equal(self.nodes[2].getbalance()[issued3['asset']], Decimal(1))

        # Basic checks of rawblindrawtransaction functionality
        blinded_addr = self.nodes[0].getnewaddress()
        addr = self.nodes[0].validateaddress(blinded_addr)["unconfidential"]
        self.nodes[0].sendtoaddress(blinded_addr, 1)
        self.nodes[0].sendtoaddress(blinded_addr, 3)
        unspent = self.nodes[0].listunspent(0, 0)
        rawtx = self.nodes[0].createrawtransaction([{"txid":unspent[0]["txid"], "vout":unspent[0]["vout"]}, {"txid":unspent[1]["txid"], "vout":unspent[1]["vout"]}], {addr:unspent[0]["amount"]+unspent[1]["amount"]-Decimal("0.2"), "fee":Decimal("0.2")})
        # Blinding will fail with 2 blinded inputs and 0 blinded outputs
        # since it has no notion of a wallet to fill in a 0-value OP_RETURN output
        try:
            self.nodes[0].rawblindrawtransaction(rawtx, [unspent[0]["amountblinder"], unspent[1]["amountblinder"]], [unspent[0]["amount"], unspent[1]["amount"]], [unspent[0]["asset"], unspent[1]["asset"]], [unspent[0]["assetblinder"], unspent[1]["assetblinder"]])
            raise AssertionError("Shouldn't be able to blind 2 input 0 output transaction via rawblindraw")
        except JSONRPCException:
            pass

        # Blinded destination added, can blind, sign and send
        rawtx = self.nodes[0].createrawtransaction([{"txid":unspent[0]["txid"], "vout":unspent[0]["vout"]}, {"txid":unspent[1]["txid"], "vout":unspent[1]["vout"]}], {blinded_addr:unspent[0]["amount"]+unspent[1]["amount"]-Decimal("0.002"), "fee":Decimal("0.002")})
        signtx = self.nodes[0].signrawtransactionwithwallet(rawtx)

        try:
            self.nodes[0].sendrawtransaction(signtx["hex"])
            raise AssertionError("Shouldn't be able to send unblinded tx with emplaced pubkey in output without additional argument")
        except JSONRPCException:
            pass

        blindtx = self.nodes[0].rawblindrawtransaction(rawtx, [unspent[0]["amountblinder"], unspent[1]["amountblinder"]], [unspent[0]["amount"], unspent[1]["amount"]], [unspent[0]["asset"], unspent[1]["asset"]], [unspent[0]["assetblinder"], unspent[1]["assetblinder"]])
        signtx = self.nodes[0].signrawtransactionwithwallet(blindtx)
        txid = self.nodes[0].sendrawtransaction(signtx["hex"])
        for output in self.nodes[0].decoderawtransaction(blindtx)["vout"]:
            if "asset" in output and output["scriptPubKey"]["type"] != "fee":
                raise AssertionError("An unblinded output exists")

        # Test fundrawtransaction with multiple assets
        issue = self.nodes[0].issueasset(1, 0)
        assetaddr = self.nodes[0].getnewaddress()
        rawtx = self.nodes[0].createrawtransaction([], {assetaddr:1, self.nodes[0].getnewaddress():2}, 0, False, {assetaddr:issue["asset"]})
        funded = self.nodes[0].fundrawtransaction(rawtx)
        blinded = self.nodes[0].blindrawtransaction(funded["hex"])
        signed = self.nodes[0].signrawtransactionwithwallet(blinded)
        txid = self.nodes[0].sendrawtransaction(signed["hex"])

        # Test fundrawtransaction with multiple inputs, creating > vout.size change
        rawtx = self.nodes[0].createrawtransaction([{"txid":txid, "vout":0}, {"txid":txid, "vout":1}], {self.nodes[0].getnewaddress():5})
        funded = self.nodes[0].fundrawtransaction(rawtx)
        blinded = self.nodes[0].blindrawtransaction(funded["hex"])
        signed = self.nodes[0].signrawtransactionwithwallet(blinded)
        txid = self.nodes[0].sendrawtransaction(signed["hex"])

        # Test corner case where wallet appends a OP_RETURN output, yet doesn't blind it
        # due to the fact that the output value is 0-value and input pedersen commitments
        # self-balance. This is rare corner case, but ok.
        unblinded = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())["unconfidential"]
        self.nodes[0].sendtoaddress(unblinded, self.nodes[0].getbalance()["bitcoin"], "", "", True)
        # Make tx with blinded destination and change outputs only
        self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[0].getbalance()["bitcoin"]/2)
        # Send back again, this transaction should have 3 outputs, all unblinded
        txid = self.nodes[0].sendtoaddress(unblinded, self.nodes[0].getbalance()["bitcoin"], "", "", True)
        outputs = self.nodes[0].getrawtransaction(txid, 1)["vout"]
        assert_equal(len(outputs), 3)
        assert("value" in outputs[0] and "value" in outputs[1] and "value" in outputs[2])
        assert_equal(outputs[2]["scriptPubKey"]["type"], 'nulldata')

        # Test burn argument in createrawtransaction
        raw_burn1 = self.nodes[0].createrawtransaction([], {self.nodes[0].getnewaddress():1, "burn":2})
        decode_burn1 = self.nodes[0].decoderawtransaction(raw_burn1)
        assert_equal(len(decode_burn1["vout"]), 2)
        found_pay = False
        found_burn = False
        for output in decode_burn1["vout"]:
            if output["scriptPubKey"]["asm"] == "OP_RETURN":
                found_burn = True
                if output["asset"] != self.nodes[0].dumpassetlabels()["bitcoin"]:
                    raise Exception("Burn should have been bitcoin(policyAsset)")
            if output["scriptPubKey"]["type"] == "scripthash":
                found_pay = True
        assert(found_pay and found_burn)

        raw_burn2 = self.nodes[0].createrawtransaction([], {self.nodes[0].getnewaddress():1, "burn":2}, 101, False, {"burn":"deadbeef"*8})
        decode_burn2 = self.nodes[0].decoderawtransaction(raw_burn2)
        assert_equal(len(decode_burn2["vout"]), 2)
        found_pay = False
        found_burn = False
        for output in decode_burn2["vout"]:
            if output["scriptPubKey"]["asm"] == "OP_RETURN":
                found_burn = True
                if output["asset"] != "deadbeef"*8:
                    raise Exception("Burn should have been deadbeef")
            if output["scriptPubKey"]["type"] == "scripthash":
                found_pay = True
        assert(found_pay and found_burn)
예제 #33
0
    def run_test(self):
        node = self.nodes[0]

        # Generate 6 keys.
        rawkeys = []
        pubkeys = []
        for i in range(6):
            raw_key = CECKey()
            raw_key.set_secretbytes(('privkey%d' % i).encode('ascii'))
            rawkeys.append(raw_key)
        pubkeys = [CPubKey(key.get_pubkey()) for key in rawkeys]

        # Create a 4-of-6 multi-sig wallet with CLTV.
        height = 210
        redeem_script = CScript(
            [CScriptNum(height), OP_CHECKLOCKTIMEVERIFY, OP_DROP
             ]  # CLTV (lock_time >= 210)
            + [OP_4] + pubkeys + [OP_6, OP_CHECKMULTISIG])  # multi-sig
        hex_redeem_script = bytes_to_hex_str(redeem_script)
        p2sh_address = script_to_p2sh(redeem_script, main=False)

        # Send 1 coin to the mult-sig wallet.
        txid = node.sendtoaddress(p2sh_address, 1.0)
        raw_tx = node.getrawtransaction(txid, True)
        try:
            node.importaddress(hex_redeem_script, 'cltv', True, True)
        except Exception:
            pass
        assert_equal(
            sig(node.getreceivedbyaddress(p2sh_address, 0) - Decimal(1.0)), 0)

        # Mine one block to confirm the transaction.
        node.generate(1)  # block 201
        assert_equal(
            sig(node.getreceivedbyaddress(p2sh_address, 1) - Decimal(1.0)), 0)

        # Try to spend the coin.
        addr_to = node.getnewaddress('')

        # (1) Find the UTXO
        for vout in raw_tx['vout']:
            if vout['scriptPubKey']['addresses'] == [p2sh_address]:
                vout_n = vout['n']
        hex_script_pubkey = raw_tx['vout'][vout_n]['scriptPubKey']['hex']
        value = raw_tx['vout'][vout_n]['value']

        # (2) Create a tx
        inputs = [{
            "txid": txid,
            "vout": vout_n,
            "scriptPubKey": hex_script_pubkey,
            "redeemScript": hex_redeem_script,
            "amount": value,
        }]
        outputs = {addr_to: 0.999}
        lock_time = height
        hex_spend_raw_tx = node.createrawtransaction(inputs, outputs,
                                                     lock_time)
        hex_funding_raw_tx = node.getrawtransaction(txid, False)

        # (3) Try to sign the spending tx.
        tx0 = CTransaction()
        tx0.deserialize(io.BytesIO(hex_str_to_bytes(hex_funding_raw_tx)))
        tx1 = CTransaction()
        tx1.deserialize(io.BytesIO(hex_str_to_bytes(hex_spend_raw_tx)))
        self.sign_tx(tx1, tx0, vout_n, redeem_script, 0,
                     rawkeys[:4])  # Sign with key[0:4]

        # Mine some blocks to pass the lock time.
        node.generate(10)

        # Spend the CLTV multi-sig coins.
        raw_tx1 = tx1.serialize()
        hex_raw_tx1 = bytes_to_hex_str(raw_tx1)
        node.sendrawtransaction(hex_raw_tx1)

        # Check the tx is accepted by mempool but not confirmed.
        assert_equal(
            sig(node.getreceivedbyaddress(addr_to, 0) - Decimal(0.999)), 0)
        assert_equal(sig(node.getreceivedbyaddress(addr_to, 1)), 0)

        # Mine a block to confirm the tx.
        node.generate(1)
        assert_equal(
            sig(node.getreceivedbyaddress(addr_to, 1) - Decimal(0.999)), 0)
예제 #34
0
    def run_test(self):
        self.log.info('prepare some coins for multiple *rawtransaction commands')
        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[0].generate(101)
        self.sync_all()
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.5)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.0)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),5.0)
        self.sync_all()
        self.nodes[0].generate(5)
        self.sync_all()

        self.log.info('Test getrawtransaction on genesis block coinbase returns an error')
        block = self.nodes[0].getblock(self.nodes[0].getblockhash(0))
        assert_raises_rpc_error(-5, "The genesis block coinbase is not considered an ordinary transaction", self.nodes[0].getrawtransaction, block['merkleroot'])

        self.log.info('Check parameter types and required parameters of createrawtransaction')
        # Test `createrawtransaction` required parameters
        assert_raises_rpc_error(-1, "createrawtransaction", self.nodes[0].createrawtransaction)
        assert_raises_rpc_error(-1, "createrawtransaction", self.nodes[0].createrawtransaction, [])

        # Test `createrawtransaction` invalid extra parameters
        assert_raises_rpc_error(-1, "createrawtransaction", self.nodes[0].createrawtransaction, [], {}, 0, False, 'foo')

        # Test `createrawtransaction` invalid `inputs`
        txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'
        assert_raises_rpc_error(-3, "Expected type array", self.nodes[0].createrawtransaction, 'foo', {})
        assert_raises_rpc_error(-1, "JSON value is not an object as expected", self.nodes[0].createrawtransaction, ['foo'], {})
        assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].createrawtransaction, [{}], {})
        assert_raises_rpc_error(-8, "txid must be of length 64 (not 3, for 'foo')", self.nodes[0].createrawtransaction, [{'txid': 'foo'}], {})
        assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')", self.nodes[0].createrawtransaction, [{'txid': 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844'}], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", self.nodes[0].createrawtransaction, [{'txid': txid}], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': 'foo'}], {})
        assert_raises_rpc_error(-8, "Invalid parameter, vout must be positive", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': -1}], {})
        assert_raises_rpc_error(-8, "Invalid parameter, sequence number is out of range", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': 0, 'sequence': -1}], {})

        # Test `createrawtransaction` invalid `outputs`
        address = self.nodes[0].getnewaddress()
        address2 = self.nodes[0].getnewaddress()
        assert_raises_rpc_error(-1, "JSON value is not an array as expected", self.nodes[0].createrawtransaction, [], 'foo')
        self.nodes[0].createrawtransaction(inputs=[], outputs={})  # Should not throw for backwards compatibility
        self.nodes[0].createrawtransaction(inputs=[], outputs=[])
        assert_raises_rpc_error(-8, "Data must be hexadecimal string", self.nodes[0].createrawtransaction, [], {'data': 'foo'})
        assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].createrawtransaction, [], {'foo': 0})
        assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].createrawtransaction, [], {address: 'foo'})
        assert_raises_rpc_error(-3, "Amount out of range", self.nodes[0].createrawtransaction, [], {address: -1})
        assert_raises_rpc_error(-8, "Invalid parameter, duplicated address: %s" % address, self.nodes[0].createrawtransaction, [], multidict([(address, 1), (address, 1)]))
        assert_raises_rpc_error(-8, "Invalid parameter, duplicated address: %s" % address, self.nodes[0].createrawtransaction, [], [{address: 1}, {address: 1}])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data", self.nodes[0].createrawtransaction, [], [{"data": 'aa'}, {"data": "bb"}])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data", self.nodes[0].createrawtransaction, [], multidict([("data", 'aa'), ("data", "bb")]))
        assert_raises_rpc_error(-8, "Invalid parameter, key-value pair must contain exactly one key", self.nodes[0].createrawtransaction, [], [{'a': 1, 'b': 2}])
        assert_raises_rpc_error(-8, "Invalid parameter, key-value pair not an object as expected", self.nodes[0].createrawtransaction, [], [['key-value pair1'], ['2']])

        # Test `createrawtransaction` invalid `locktime`
        assert_raises_rpc_error(-3, "Expected type number", self.nodes[0].createrawtransaction, [], {}, 'foo')
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range", self.nodes[0].createrawtransaction, [], {}, -1)
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range", self.nodes[0].createrawtransaction, [], {}, 4294967296)

        # Test `createrawtransaction` invalid `replaceable`
        assert_raises_rpc_error(-3, "Expected type bool", self.nodes[0].createrawtransaction, [], {}, 0, 'foo')

        self.log.info('Check that createrawtransaction accepts an array and object as outputs')
        tx = CTransaction()
        # One output
        tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs={address: 99}))))
        assert_equal(len(tx.vout), 1)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}]),
        )
        # Two outputs
        tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=OrderedDict([(address, 99), (address2, 99)])))))
        assert_equal(len(tx.vout), 2)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}, {address2: 99}]),
        )
        # Multiple mixed outputs
        tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=multidict([(address, 99), (address2, 99), ('data', '99')])))))
        assert_equal(len(tx.vout), 3)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}, {address2: 99}, {'data': '99'}]),
        )

        for type in ["bech32", "p2sh-segwit", "legacy"]:
            addr = self.nodes[0].getnewaddress("", type)
            addrinfo = self.nodes[0].getaddressinfo(addr)
            pubkey = addrinfo["scriptPubKey"]

            self.log.info('sendrawtransaction with missing prevtx info (%s)' %(type))

            # Test `signrawtransactionwithwallet` invalid `prevtxs`
            inputs  = [ {'txid' : txid, 'vout' : 3, 'sequence' : 1000}]
            outputs = { self.nodes[0].getnewaddress() : 1 }
            rawtx   = self.nodes[0].createrawtransaction(inputs, outputs)

            prevtx = dict(txid=txid, scriptPubKey=pubkey, vout=3, amount=1)
            succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx])
            assert succ["complete"]
            if type == "legacy":
                del prevtx["amount"]
                succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx])
                assert succ["complete"]

            if type != "legacy":
                assert_raises_rpc_error(-3, "Missing amount", self.nodes[0].signrawtransactionwithwallet, rawtx, [
                    {
                        "txid": txid,
                        "scriptPubKey": pubkey,
                        "vout": 3,
                    }
                ])

            assert_raises_rpc_error(-3, "Missing vout", self.nodes[0].signrawtransactionwithwallet, rawtx, [
                {
                    "txid": txid,
                    "scriptPubKey": pubkey,
                    "amount": 1,
                }
            ])
            assert_raises_rpc_error(-3, "Missing txid", self.nodes[0].signrawtransactionwithwallet, rawtx, [
                {
                    "scriptPubKey": pubkey,
                    "vout": 3,
                    "amount": 1,
                }
            ])
            assert_raises_rpc_error(-3, "Missing scriptPubKey", self.nodes[0].signrawtransactionwithwallet, rawtx, [
                {
                    "txid": txid,
                    "vout": 3,
                    "amount": 1
                }
            ])

        #########################################
        # sendrawtransaction with missing input #
        #########################################

        self.log.info('sendrawtransaction with missing input')
        inputs  = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1}] #won't exists
        outputs = { self.nodes[0].getnewaddress() : 4.998 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx   = self.nodes[2].signrawtransactionwithwallet(rawtx)

        # This will raise an exception since there are missing inputs
        assert_raises_rpc_error(-25, "Missing inputs", self.nodes[2].sendrawtransaction, rawtx['hex'])

        #####################################
        # getrawtransaction with block hash #
        #####################################

        # make a tx by sending then generate 2 blocks; block1 has the tx in it
        tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        block1, block2 = self.nodes[2].generate(2)
        self.sync_all()
        # We should be able to get the raw transaction by providing the correct block
        gottx = self.nodes[0].getrawtransaction(tx, True, block1)
        assert_equal(gottx['txid'], tx)
        assert_equal(gottx['in_active_chain'], True)
        # We should not have the 'in_active_chain' flag when we don't provide a block
        gottx = self.nodes[0].getrawtransaction(tx, True)
        assert_equal(gottx['txid'], tx)
        assert 'in_active_chain' not in gottx
        # We should not get the tx if we provide an unrelated block
        assert_raises_rpc_error(-5, "No such transaction found", self.nodes[0].getrawtransaction, tx, True, block2)
        # An invalid block hash should raise the correct errors
        assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].getrawtransaction, tx, True, True)
        assert_raises_rpc_error(-8, "parameter 3 must be of length 64 (not 6, for 'foobar')", self.nodes[0].getrawtransaction, tx, True, "foobar")
        assert_raises_rpc_error(-8, "parameter 3 must be of length 64 (not 8, for 'abcd1234')", self.nodes[0].getrawtransaction, tx, True, "abcd1234")
        assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].getrawtransaction, tx, True, "ZZZ0000000000000000000000000000000000000000000000000000000000000")
        assert_raises_rpc_error(-5, "Block hash not found", self.nodes[0].getrawtransaction, tx, True, "0000000000000000000000000000000000000000000000000000000000000000")
        # Undo the blocks and check in_active_chain
        self.nodes[0].invalidateblock(block1)
        gottx = self.nodes[0].getrawtransaction(txid=tx, verbose=True, blockhash=block1)
        assert_equal(gottx['in_active_chain'], False)
        self.nodes[0].reconsiderblock(block1)
        assert_equal(self.nodes[0].getbestblockhash(), block2)

        #########################
        # RAW TX MULTISIG TESTS #
        #########################
        # 2of2 test
        addr1 = self.nodes[2].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[2].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        # Tests for createmultisig and addmultisigaddress
        assert_raises_rpc_error(-5, "Invalid public key", self.nodes[0].createmultisig, 1, ["01020304"])
        self.nodes[0].createmultisig(2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) # createmultisig can only take public keys
        assert_raises_rpc_error(-5, "Invalid public key", self.nodes[0].createmultisig, 2, [addr1Obj['pubkey'], addr1]) # addmultisigaddress can take both pubkeys and addresses so long as they are in the wallet, which is tested here.

        mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr1])['address']

        #use balance deltas instead of absolute values
        bal = self.nodes[2].getbalance()

        # send 1.2 BTC to msig adr
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), bal+Decimal('1.20000000')) #node2 has both keys of the 2of2 ms addr., tx should affect the balance


        # 2of3 test from different nodes
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()
        addr3 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)
        addr3Obj = self.nodes[2].getaddressinfo(addr3)

        mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']])['address']

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        #THIS IS AN INCOMPLETE FEATURE
        #NODE2 HAS TWO OF THREE KEY AND THE FUNDS SHOULD BE SPENDABLE AND COUNT AT BALANCE CALCULATION
        assert_equal(self.nodes[2].getbalance(), bal) #for now, assume the funds of a 2of3 multisig tx are not marked as spendable

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = False
        for outpoint in rawTx['vout']:
            if outpoint['value'] == Decimal('2.20000000'):
                vout = outpoint
                break

        bal = self.nodes[0].getbalance()
        inputs = [{ "txid" : txId, "vout" : vout['n'], "scriptPubKey" : vout['scriptPubKey']['hex'], "amount" : vout['value']}]
        outputs = { self.nodes[0].getnewaddress() : 2.19 }
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned = self.nodes[1].signrawtransactionwithwallet(rawTx, inputs)
        assert_equal(rawTxPartialSigned['complete'], False) #node1 only has one key, can't comp. sign the tx

        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx, inputs)
        assert_equal(rawTxSigned['complete'], True) #node2 can sign the tx compl., own two of three keys
        self.nodes[2].sendrawtransaction(rawTxSigned['hex'])
        rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal+Decimal('50.00000000')+Decimal('2.19000000')) #block reward + tx

        # 2of2 test for combining transactions
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        self.nodes[1].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObjValid = self.nodes[2].getaddressinfo(mSigObj)

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        assert_equal(self.nodes[2].getbalance(), bal) # the funds of a 2of2 multisig tx should not be marked as spendable

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = False
        for outpoint in rawTx2['vout']:
            if outpoint['value'] == Decimal('2.20000000'):
                vout = outpoint
                break

        bal = self.nodes[0].getbalance()
        inputs = [{ "txid" : txId, "vout" : vout['n'], "scriptPubKey" : vout['scriptPubKey']['hex'], "redeemScript" : mSigObjValid['hex'], "amount" : vout['value']}]
        outputs = { self.nodes[0].getnewaddress() : 2.19 }
        rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned1 = self.nodes[1].signrawtransactionwithwallet(rawTx2, inputs)
        self.log.debug(rawTxPartialSigned1)
        assert_equal(rawTxPartialSigned1['complete'], False) #node1 only has one key, can't comp. sign the tx

        rawTxPartialSigned2 = self.nodes[2].signrawtransactionwithwallet(rawTx2, inputs)
        self.log.debug(rawTxPartialSigned2)
        assert_equal(rawTxPartialSigned2['complete'], False) #node2 only has one key, can't comp. sign the tx
        rawTxComb = self.nodes[2].combinerawtransaction([rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']])
        self.log.debug(rawTxComb)
        self.nodes[2].sendrawtransaction(rawTxComb)
        rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal+Decimal('50.00000000')+Decimal('2.19000000')) #block reward + tx

        # decoderawtransaction tests
        # witness transaction
        encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000"
        decrawtx = self.nodes[0].decoderawtransaction(encrawtx, True) # decode as witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
        assert_raises_rpc_error(-22, 'TX decode failed', self.nodes[0].decoderawtransaction, encrawtx, False) # force decode as non-witness transaction
        # non-witness transaction
        encrawtx = "01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000"
        decrawtx = self.nodes[0].decoderawtransaction(encrawtx, False) # decode as non-witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))

        # getrawtransaction tests
        # 1. valid parameters - only supply txid
        txHash = rawTx["hash"]
        assert_equal(self.nodes[0].getrawtransaction(txHash), rawTxSigned['hex'])

        # 2. valid parameters - supply txid and 0 for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, 0), rawTxSigned['hex'])

        # 3. valid parameters - supply txid and False for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, False), rawTxSigned['hex'])

        # 4. valid parameters - supply txid and 1 for verbose.
        # We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
        assert_equal(self.nodes[0].getrawtransaction(txHash, 1)["hex"], rawTxSigned['hex'])

        # 5. valid parameters - supply txid and True for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"], rawTxSigned['hex'])

        # 6. invalid parameters - supply txid and string "Flase"
        assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txHash, "Flase")

        # 7. invalid parameters - supply txid and empty array
        assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txHash, [])

        # 8. invalid parameters - supply txid and empty dict
        assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txHash, {})

        inputs  = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}]
        outputs = { self.nodes[0].getnewaddress() : 1 }
        rawtx   = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx= self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 1000)

        # 9. invalid parameters - sequence number out of range
        inputs  = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : -1}]
        outputs = { self.nodes[0].getnewaddress() : 1 }
        assert_raises_rpc_error(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs)

        # 10. invalid parameters - sequence number out of range
        inputs  = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967296}]
        outputs = { self.nodes[0].getnewaddress() : 1 }
        assert_raises_rpc_error(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs)

        inputs  = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967294}]
        outputs = { self.nodes[0].getnewaddress() : 1 }
        rawtx   = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx= self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 4294967294)

        ####################################
        # TRANSACTION VERSION NUMBER TESTS #
        ####################################

        # Test the minimum transaction version number that fits in a signed 32-bit integer.
        tx = CTransaction()
        tx.nVersion = -0x80000000
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], -0x80000000)

        # Test the maximum transaction version number that fits in a signed 32-bit integer.
        tx = CTransaction()
        tx.nVersion = 0x7fffffff
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], 0x7fffffff)
    def run_test(self):
        node = self.nodes[0]
        node.add_p2p_connection(P2PDataStore())
        # Allocate as many UTXOs as are needed
        num_utxos = sum(
            len(test_case['sig_hash_types']) for test_case in TESTCASES
            if isinstance(test_case, dict))

        value = int(SUBSIDY * 1_000_000)
        fee = 10_000

        max_utxo_value = (value - fee) // num_utxos
        private_keys = []
        public_keys = []
        spendable_outputs = []
        executed_scripts = []
        utxo_idx = 0
        # Prepare UTXOs for the tests below
        for test_case in TESTCASES:
            if test_case == 'ENABLE_REPLAY_PROTECTION':
                continue
            for _ in test_case['sig_hash_types']:
                private_key = ECKey()
                private_key.generate()
                private_keys.append(private_key)
                public_key = private_key.get_pubkey()
                public_keys.append(public_key)
                utxo_value = max_utxo_value - utxo_idx * 100  # deduct 100*i coins for unique amounts
                if test_case.get('opcodes', False):
                    opcodes = test_case['opcodes']
                    redeem_script = CScript(
                        opcodes + [public_key.get_bytes(), OP_CHECKSIG])
                    executed_scripts.append(redeem_script)
                    utxo_script = CScript(
                        [OP_HASH160,
                         hash160(redeem_script), OP_EQUAL])
                elif test_case.get('is_p2pk', False):
                    utxo_script = CScript(
                        [public_key.get_bytes(), OP_CHECKSIG])
                    executed_scripts.append(utxo_script)
                else:
                    utxo_script = CScript([
                        OP_DUP, OP_HASH160,
                        hash160(public_key.get_bytes()), OP_EQUALVERIFY,
                        OP_CHECKSIG
                    ])
                    executed_scripts.append(utxo_script)
                spendable_outputs.append(CTxOut(utxo_value, utxo_script))
                utxo_idx += 1

        anyonecanspend_address = node.decodescript('51')['p2sh']
        burn_address = node.decodescript('00')['p2sh']
        p2sh_script = CScript([OP_HASH160, bytes(20), OP_EQUAL])
        node.generatetoaddress(1, anyonecanspend_address)
        node.generatetoaddress(100, burn_address)

        # Build and send fan-out transaction creating all the UTXOs
        block_hash = node.getblockhash(1)
        coin = int(node.getblock(block_hash)['tx'][0], 16)
        tx_fan_out = CTransaction()
        tx_fan_out.vin.append(CTxIn(COutPoint(coin, 1), CScript([b'\x51'])))
        tx_fan_out.vout = spendable_outputs
        tx_fan_out.rehash()

        node.p2p.send_txs_and_test([tx_fan_out], node)

        utxo_idx = 0
        key_idx = 0
        for test_case in TESTCASES:
            if test_case == 'ENABLE_REPLAY_PROTECTION':
                node.setmocktime(ACTIVATION_TIME)
                node.generatetoaddress(11, burn_address)
                continue
            # Build tx for this test, will broadcast later
            tx = CTransaction()
            num_inputs = len(test_case['sig_hash_types'])
            spent_outputs = spendable_outputs[:num_inputs]
            del spendable_outputs[:num_inputs]
            assert len(spent_outputs) == num_inputs
            total_input_amount = sum(output.nValue for output in spent_outputs)
            max_output_amount = (total_input_amount -
                                 fee) // test_case['outputs']
            for i in range(test_case['outputs']):
                output_amount = max_output_amount - i * 77
                output_script = CScript(
                    [OP_HASH160, i.to_bytes(20, 'big'), OP_EQUAL])
                tx.vout.append(CTxOut(output_amount, output_script))
            for _ in test_case['sig_hash_types']:
                tx.vin.append(
                    CTxIn(COutPoint(tx_fan_out.txid, utxo_idx), CScript()))
                utxo_idx += 1
            # Keep unsigned tx for signrawtransactionwithkey below
            unsigned_tx = tx.serialize().hex()
            private_keys_wif = []
            sign_inputs = []
            # Make list of inputs for signrawtransactionwithkey
            for i, spent_output in enumerate(spent_outputs):
                sign_inputs.append({
                    'txid':
                    tx_fan_out.txid_hex,
                    'vout':
                    key_idx + i,
                    'amount':
                    Decimal(spent_output.nValue) / COIN,
                    'scriptPubKey':
                    spent_output.scriptPubKey.hex(),
                })
            for i, sig_hash_type in enumerate(test_case['sig_hash_types']):
                # Compute sighash for this input; we sign it manually using sign_ecdsa/sign_schnorr
                # and then broadcast the complete transaction
                sighash = SignatureHashLotus(
                    tx_to=tx,
                    spent_utxos=spent_outputs,
                    sig_hash_type=sig_hash_type,
                    input_index=i,
                    executed_script_hash=hash256(executed_scripts[key_idx]),
                    codeseparator_pos=test_case.get('codesep', 0xffff_ffff),
                )
                if test_case.get('schnorr', False):
                    signature = private_keys[key_idx].sign_schnorr(sighash)
                else:
                    signature = private_keys[key_idx].sign_ecdsa(sighash)
                signature += bytes(
                    [test_case.get('suffix', sig_hash_type & 0xff)])
                # Build correct scriptSig
                if test_case.get('opcodes'):
                    tx.vin[i].scriptSig = CScript(
                        [signature, executed_scripts[key_idx]])
                elif test_case.get('is_p2pk'):
                    tx.vin[i].scriptSig = CScript([signature])
                else:
                    tx.vin[i].scriptSig = CScript(
                        [signature, public_keys[key_idx].get_bytes()])

                sig_hash_type_str = self.get_sig_hash_type_str(sig_hash_type)
                if sig_hash_type_str is not None and 'opcodes' not in test_case and 'error' not in test_case:
                    # If we're a simple output type (P2PKH or P2KH) and aren't supposed to fail,
                    # we sign using signrawtransactionwithkey and verify the transaction signed
                    # the expected sighash. We won't broadcast it though.
                    # Note: signrawtransactionwithkey will not sign using replay-protection.
                    private_key_wif = bytes_to_wif(
                        private_keys[key_idx].get_bytes())
                    raw_tx_signed = self.nodes[0].signrawtransactionwithkey(
                        unsigned_tx, [private_key_wif], sign_inputs,
                        sig_hash_type_str)['hex']
                    # Extract signature from signed
                    signed_tx = CTransaction()
                    signed_tx.deserialize(
                        io.BytesIO(bytes.fromhex(raw_tx_signed)))
                    sig = list(CScript(signed_tx.vin[i].scriptSig))[0]
                    pubkey = private_keys[key_idx].get_pubkey()
                    sighash = SignatureHashLotus(
                        tx_to=tx,
                        spent_utxos=spent_outputs,
                        sig_hash_type=sig_hash_type & 0xff,
                        input_index=i,
                        executed_script_hash=hash256(
                            executed_scripts[key_idx]),
                    )
                    # Verify sig signs the above sighash and has the expected sighash type
                    assert pubkey.verify_ecdsa(sig[:-1], sighash)
                    assert sig[-1] == sig_hash_type & 0xff
                key_idx += 1
            # Broadcast transaction and check success/failure
            tx.rehash()
            if 'error' not in test_case:
                node.p2p.send_txs_and_test([tx], node)
            else:
                node.p2p.send_txs_and_test([tx],
                                           node,
                                           success=False,
                                           reject_reason=test_case['error'])