def reissue_prec_change(self):
        self.log.info("Testing precision change on reissue...")
        n0 = self.nodes[0]

        asset_name = "PREC_CHANGES"
        address = n0.getnewaddress()

        n0.issue(asset_name, 10, "", "", 0, True, False)
        n0.generate(1)
        assert_equal(0, n0.listassets("*", True)[asset_name]["units"])

        for i in range(0, 8):
            n0.reissue(asset_name, 10.0**(-i), address, "", True, i + 1)
            n0.generate(1)
            assert_equal(i + 1, n0.listassets("*", True)[asset_name]["units"])
            assert_raises_rpc_error(
                -25,
                "Error: Unable to reissue asset: unit must be larger than current unit selection",
                n0.reissue, asset_name, 10.0**(-i), address, "", True, i)

        n0.reissue(asset_name, 0.00000001, address)
        n0.generate(1)
        assert_equal(Decimal('11.11111111'),
                     n0.listassets("*", True)[asset_name]["amount"])
Beispiel #2
0
    def test_coin_selection(self):
        self.log.info("test with a vin < required amount")
        utx = get_unspent(self.nodes[2].listunspent(), 1)
        inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        outputs = {self.nodes[0].getnewaddress(): 1.0}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)

        # 4-byte version + 1-byte vin count + 36-byte prevout then script_len
        rawtx = rawtx[:82] + "0100" + rawtx[84:]

        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
        assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        changepos = rawtxfund['changepos']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        assert_equal(len(dec_tx['vin']) > 0, True)                  # test if we have enought inputs
        assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])    # check vin sig again
        assert_equal(len(dec_tx['vout']), 2)
        assert_greater_than(changepos, -1)                          # check change
        assert_equal(Decimal(dec_tx['vout'][changepos]['value']) + fee, DecimalAmt(1.5))
        assert check_outputs(outputs, dec_tx)                       # check outputs
 def create_bip68txs(self, bip68inputs, txversion, locktime_delta=0):
     txs = []
     assert (len(bip68inputs) >= 16)
     i = 0
     for b31 in range(2):
         b25txs = []
         for b25 in range(2):
             b22txs = []
             for b22 in range(2):
                 b18txs = []
                 for b18 in range(2):
                     tx = self.create_transaction(self.nodes[0],
                                                  bip68inputs[i],
                                                  self.nodeaddress,
                                                  Decimal("49.98"))
                     i += 1
                     tx.nVersion = txversion
                     tx.vin[0].nSequence = relative_locktimes[b31][b25][
                         b22][b18] + locktime_delta
                     b18txs.append(self.sign_transaction(self.nodes[0], tx))
                 b22txs.append(b18txs)
             b25txs.append(b22txs)
         txs.append(b25txs)
     return txs
Beispiel #4
0
    def run_test(self):
        ''' Started from PoW cache. '''
        utxo = self.nodes[0].listunspent(10)
        txid = utxo[0]['txid']
        vout = utxo[0]['vout']
        value = utxo[0]['amount']

        fee = Decimal("0.0001")
        # MAX_ANCESTORS transactions off a confirmed tx should be fine
        chain = []
        for i in range(MAX_ANCESTORS):
            (txid,
             sent_value) = self.chain_transaction(self.nodes[0], txid, 0,
                                                  value, fee, 1)
            value = sent_value
            chain.append(txid)

        # Check mempool has MAX_ANCESTORS transactions in it, and descendant
        # count and fees should look correct
        mempool = self.nodes[0].getrawmempool(True)
        assert_equal(len(mempool), MAX_ANCESTORS)
        descendant_count = 1
        descendant_fees = 0
        descendant_size = 0
        SATOSHIS = 100000000

        for x in reversed(chain):
            assert_equal(mempool[x]['descendantcount'], descendant_count)
            descendant_fees += mempool[x]['fee']
            assert_equal(mempool[x]['descendantfees'],
                         SATOSHIS * descendant_fees)
            descendant_size += mempool[x]['size']
            assert_equal(mempool[x]['descendantsize'], descendant_size)
            descendant_count += 1

        # Adding one more transaction on to the chain should fail.
        try:
            self.chain_transaction(self.nodes[0], txid, vout, value, fee, 1)
        except JSONRPCException as e:
            self.log.info("too-long-ancestor-chain successfully rejected")

        # TODO: check that node1's mempool is as expected

        # TODO: test ancestor size limits

        # Now test descendant chain limits
        txid = utxo[1]['txid']
        value = utxo[1]['amount']
        vout = utxo[1]['vout']

        transaction_package = []
        # First create one parent tx with 10 children
        (txid, sent_value) = self.chain_transaction(self.nodes[0], txid, vout,
                                                    value, fee, 10)
        parent_transaction = txid
        for i in range(10):
            transaction_package.append({
                'txid': txid,
                'vout': i,
                'amount': sent_value
            })

        for i in range(MAX_DESCENDANTS):
            utxo = transaction_package.pop(0)
            try:
                (txid, sent_value) = self.chain_transaction(
                    self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'],
                    fee, 10)
                for j in range(10):
                    transaction_package.append({
                        'txid': txid,
                        'vout': j,
                        'amount': sent_value
                    })
                if i == MAX_DESCENDANTS - 2:
                    mempool = self.nodes[0].getrawmempool(True)
                    assert_equal(
                        mempool[parent_transaction]['descendantcount'],
                        MAX_DESCENDANTS)
            except JSONRPCException as e:
                self.log.info(e.error['message'])
                assert_equal(i, MAX_DESCENDANTS - 1)
                self.log.info(
                    "tx that would create too large descendant package successfully rejected"
                )

        # TODO: check that node1's mempool is as expected

        # TODO: test descendant size limits

        # Test reorg handling
        # First, the basics:
        self.nodes[0].generate(1)
        sync_blocks(self.nodes)
        self.nodes[1].invalidateblock(self.nodes[0].getbestblockhash())
        self.nodes[1].reconsiderblock(self.nodes[0].getbestblockhash())

        # Now test the case where node1 has a transaction T in its mempool that
        # depends on transactions A and B which are in a mined block, and the
        # block containing A and B is disconnected, AND B is not accepted back
        # into node1's mempool because its ancestor count is too high.

        # Create 8 transactions, like so:
        # Tx0 -> Tx1 (vout0)
        #   \--> Tx2 (vout1) -> Tx3 -> Tx4 -> Tx5 -> Tx6 -> Tx7
        #
        # Mine them in the next block, then generate a new tx8 that spends
        # Tx1 and Tx7, and add to node1's mempool, then disconnect the
        # last block.

        # Create tx0 with 2 outputs
        utxo = self.nodes[0].listunspent()
        txid = utxo[0]['txid']
        value = utxo[0]['amount']
        vout = utxo[0]['vout']

        send_value = satoshi_round((value - fee) / 2)
        inputs = [{'txid': txid, 'vout': vout}]
        outputs = {}
        for i in range(2):
            outputs[self.nodes[0].getnewaddress()] = float(send_value)
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        signedtx = self.nodes[0].signrawtransaction(rawtx)
        txid = self.nodes[0].sendrawtransaction(signedtx['hex'])
        tx0_id = txid
        value = send_value

        # Create tx1
        (tx1_id, tx1_value) = self.chain_transaction(self.nodes[0], tx0_id, 0,
                                                     value, fee, 1)

        # Create tx2-7
        vout = 1
        txid = tx0_id
        for i in range(6):
            (txid,
             sent_value) = self.chain_transaction(self.nodes[0], txid, vout,
                                                  value, fee, 1)
            vout = 0
            value = sent_value

        # Mine these in a block
        self.nodes[0].generate(1)
        self.sync_all()

        # Now generate tx8, with a big fee
        inputs = [{'txid': tx1_id, 'vout': 0}, {'txid': txid, 'vout': 0}]
        outputs = {self.nodes[0].getnewaddress(): send_value + value - 4 * fee}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        signedtx = self.nodes[0].signrawtransaction(rawtx)
        txid = self.nodes[0].sendrawtransaction(signedtx['hex'])
        sync_mempools(self.nodes)

        # Now try to disconnect the tip on each node...
        self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())
        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
        sync_blocks(self.nodes)
Beispiel #5
0
def assert_close(f1, f2):
    assert (abs(Decimal(f1) - f2) < 0.1)
    def test_compactblock_construction(self, node, test_node, version,
                                       use_witness_address):
        # Generate a bunch of transactions.
        node.generate(101)
        num_transactions = 25
        address = node.getnewaddress()
        if use_witness_address:
            # Want at least one segwit spend, so move all funds to
            # a witness address.
            address = node.addwitnessaddress(address)
            value_to_send = node.getbalance()
            node.sendtoaddress(address,
                               satoshi_round(value_to_send - Decimal(0.1)))
            node.generate(1)

        segwit_tx_generated = False
        for _ in range(num_transactions):
            txid = node.sendtoaddress(address, 0.1)
            hex_tx = node.gettransaction(txid)["hex"]
            tx = from_hex(CTransaction(), hex_tx)
            if not tx.wit.is_null():
                segwit_tx_generated = True

        if use_witness_address:
            assert segwit_tx_generated  # check that our test is not broken

        # Wait until we've seen the block announcement for the resulting tip
        tip = int(node.getbestblockhash(), 16)
        test_node.wait_for_block_announcement(tip)

        # Make sure we will receive a fast-announce compact block
        self.request_cb_announcements(test_node, node, version)

        # Now mine a block, and look at the resulting compact block.
        test_node.clear_block_announcement()
        block_hash = int(node.generate(1)[0], 16)

        # Store the raw block in our internal format.
        block = from_hex(CBlock(), node.getblock("%02x" % block_hash, False))
        for tx in block.vtx:
            tx.calc_x16r()
        block.rehash()

        # Wait until the block was announced (via compact blocks)
        wait_until(test_node.received_block_announcement,
                   timeout=30,
                   lock=mininode_lock,
                   err_msg="test_node.received_block_announcement")

        # Now fetch and check the compact block
        with mininode_lock:
            assert ("cmpctblock" in test_node.last_message)
            # Convert the on-the-wire representation to absolute indexes
            header_and_shortids = HeaderAndShortIDs(
                test_node.last_message["cmpctblock"].header_and_shortids)
        self.check_compactblock_construction_from_block(
            version, header_and_shortids, block_hash, block)

        # Now fetch the compact block using a normal non-announce getdata
        with mininode_lock:
            test_node.clear_block_announcement()
            inv = CInv(4, block_hash)  # 4 == "CompactBlock"
            test_node.send_message(MsgGetdata([inv]))

        wait_until(test_node.received_block_announcement,
                   timeout=30,
                   lock=mininode_lock,
                   err_msg="test_node.received_block_announcement")

        # Now fetch and check the compact block
        with mininode_lock:
            assert ("cmpctblock" in test_node.last_message)
            # Convert the on-the-wire representation to absolute indexes
            header_and_shortids = HeaderAndShortIDs(
                test_node.last_message["cmpctblock"].header_and_shortids)
        self.check_compactblock_construction_from_block(
            version, header_and_shortids, block_hash, block)
    def run_test(self):
        self.enable_mocktime()
        self.setup_2_masternodes_network()

        # Prepare the proposal
        self.log.info("preparing budget proposal..")
        firstProposalName = "super-cool"
        firstProposalLink = "https://forum.flitswallet.app/t/test-proposal"
        firstProposalCycles = 2
        firstProposalAddress = self.miner.getnewaddress()
        firstProposalAmountPerCycle = 300
        nextSuperBlockHeight = self.miner.getnextsuperblock()

        proposalFeeTxId = self.miner.preparebudget(
            firstProposalName, firstProposalLink, firstProposalCycles,
            nextSuperBlockHeight, firstProposalAddress,
            firstProposalAmountPerCycle)

        # generate 3 blocks to confirm the tx (and update the mnping)
        self.stake(3, [self.remoteOne, self.remoteTwo])

        # activate sporks
        self.activate_spork(self.minerPos,
                            "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT")
        self.activate_spork(self.minerPos,
                            "SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT")
        self.activate_spork(self.minerPos, "SPORK_13_ENABLE_SUPERBLOCKS")

        txinfo = self.miner.gettransaction(proposalFeeTxId)
        assert_equal(txinfo['amount'], -50.00)

        self.log.info("submitting the budget proposal..")

        proposalHash = self.miner.submitbudget(
            firstProposalName, firstProposalLink, firstProposalCycles,
            nextSuperBlockHeight, firstProposalAddress,
            firstProposalAmountPerCycle, proposalFeeTxId)

        # let's wait a little bit and see if all nodes are sync
        time.sleep(1)
        self.check_proposal_existence(firstProposalName, proposalHash)
        self.log.info("proposal broadcast successful!")

        # Proposal is established after 5 minutes. Mine 7 blocks
        # Proposal needs to be on the chain > 5 min.
        self.stake(7, [self.remoteOne, self.remoteTwo])

        # now let's vote for the proposal with the first MN
        self.log.info("broadcasting votes for the proposal now..")
        voteResult = self.ownerOne.mnbudgetvote("alias", proposalHash, "yes",
                                                self.masternodeOneAlias)
        assert_equal(voteResult["detail"][0]["result"], "success")

        # check that the vote was accepted everywhere
        self.stake(1, [self.remoteOne, self.remoteTwo])
        self.check_vote_existence(firstProposalName, self.mnOneTxHash, "YES")
        self.log.info("all good, MN1 vote accepted everywhere!")

        # now let's vote for the proposal with the second MN
        voteResult = self.ownerTwo.mnbudgetvote("alias", proposalHash, "yes",
                                                self.masternodeTwoAlias)
        assert_equal(voteResult["detail"][0]["result"], "success")

        # check that the vote was accepted everywhere
        self.stake(1, [self.remoteOne, self.remoteTwo])
        self.check_vote_existence(firstProposalName, self.mnTwoTxHash, "YES")
        self.log.info("all good, MN2 vote accepted everywhere!")

        # Now check the budget
        blockStart = nextSuperBlockHeight
        blockEnd = blockStart + firstProposalCycles * 145
        TotalPayment = firstProposalAmountPerCycle * firstProposalCycles
        Allotted = firstProposalAmountPerCycle
        RemainingPaymentCount = firstProposalCycles
        expected_budget = [
            self.get_proposal_obj(firstProposalName, firstProposalLink,
                                  proposalHash, proposalFeeTxId, blockStart,
                                  blockEnd, firstProposalCycles,
                                  RemainingPaymentCount, firstProposalAddress,
                                  1, 2, 0, 0, Decimal(str(TotalPayment)),
                                  Decimal(str(firstProposalAmountPerCycle)),
                                  True, True, Decimal(str(Allotted)),
                                  Decimal(str(Allotted)))
        ]
        self.check_budgetprojection(expected_budget)

        # Quick block count check.
        assert_equal(self.ownerOne.getblockcount(), 276)

        self.log.info("starting budget finalization sync test..")
        self.stake(5, [self.remoteOne, self.remoteTwo])

        # assert that there is no budget finalization first.
        assert_true(len(self.ownerOne.mnfinalbudget("show")) == 0)

        # suggest the budget finalization and confirm the tx (+4 blocks).
        budgetFinHash = self.broadcastbudgetfinalization(
            self.miner, with_ping_mns=[self.remoteOne, self.remoteTwo])
        assert (budgetFinHash != "")
        time.sleep(1)

        self.log.info("checking budget finalization sync..")
        self.check_budget_finalization_sync(0, "OK")

        self.log.info(
            "budget finalization synced!, now voting for the budget finalization.."
        )

        self.ownerOne.mnfinalbudget("vote-many", budgetFinHash)
        self.ownerTwo.mnfinalbudget("vote-many", budgetFinHash)
        self.stake(2, [self.remoteOne, self.remoteTwo])

        self.log.info("checking finalization votes..")
        self.check_budget_finalization_sync(2, "OK")

        self.stake(8, [self.remoteOne, self.remoteTwo])
        addrInfo = self.miner.listreceivedbyaddress(0, False, False,
                                                    firstProposalAddress)
        assert_equal(addrInfo[0]["amount"], firstProposalAmountPerCycle)

        self.log.info("budget proposal paid!, all good")

        # Check that the proposal info returns updated payment count
        expected_budget[0]["RemainingPaymentCount"] -= 1
        self.check_budgetprojection(expected_budget)
Beispiel #8
0
 def fail_mine(self, node, txid, sign, redeem_script=""):
     send_to_witness(1, node, getutxo(txid), self.pubkey[0], False,
                     Decimal("4999.8"), sign, redeem_script)
     assert_raises_rpc_error(-1, "CreateNewBlock: TestBlockValidity failed",
                             node.generate, 1)
     sync_blocks(self.nodes)
Beispiel #9
0
 def skip_mine(self, node, txid, sign, redeem_script=""):
     send_to_witness(1, node, getutxo(txid), self.pubkey[0], False,
                     Decimal("4999.8"), sign, redeem_script)
     block = node.generate(1)
     assert_equal(len(node.getblock(block[0])["tx"]), 1)
     sync_blocks(self.nodes)
Beispiel #10
0
    def run_test(self):

        # Give novalidate 50 BTC
        self.nodes[i_novalidate].generate(101)
        self.sync_all()

        # This function tests the result of the getpakinfo RPC.
        # *_pak is either False (undefined paklist), "reject" or a list of
        # (online, offline) tuples
        def test_pak(node, config_pak, block_pak, validate):
            getpakinfo = node.getpakinfo()

            def compare(actual, expected):
                if expected is False:
                    assert_equal(actual, {})
                elif "reject" in expected:
                    assert_equal(actual['offline'], [])
                    assert_equal(actual['online'], [])
                    assert_equal(actual['reject'], True)
                else:
                    offline = list(map(lambda x: x[0], expected))
                    online = list(map(lambda x: x[1], expected))
                    assert_equal(actual['offline'], offline)
                    assert_equal(actual['online'], online)
                    assert_equal(actual['reject'], False)

            compare(getpakinfo['config_paklist'], config_pak)
            compare(getpakinfo['block_paklist'], block_pak)

        # In the beginning the blockchain paklist is "reject"
        test_pak(self.nodes[i_novalidate], pak1, "reject", False)
        test_pak(self.nodes[i_undefined], False, "reject", True)
        test_pak(self.nodes[i_pak1], pak1, "reject", True)
        test_pak(self.nodes[i_pak2], pak2, "reject", True)
        test_pak(self.nodes[i_reject], "reject", "reject", True)

        # i_novalidate creates block without a commitment
        block_proposal = self.nodes[i_novalidate].getnewblockhex()
        assert_equal(
            self.nodes[i_novalidate].testproposedblock(block_proposal), None)
        assert_equal(self.nodes[i_undefined].testproposedblock(block_proposal),
                     None)

        assert_raises_rpc_error(
            -25, "Proposal does not have required PAK commitment.",
            self.nodes[i_pak1].testproposedblock, block_proposal)

        # i_undefined creates a block without a commitment
        block_proposal = self.nodes[i_undefined].getnewblockhex()
        assert_equal(
            self.nodes[i_novalidate].testproposedblock(block_proposal), None)
        assert_equal(self.nodes[i_undefined].testproposedblock(block_proposal),
                     None)

        assert_raises_rpc_error(
            -25, "Proposal does not have required PAK commitment.",
            self.nodes[i_pak1].testproposedblock, block_proposal)

        # PAK transition: reject -> pak1
        # Create a new block with node i_pak1. Because it contains a commitment
        # to pak1 it should be rejected by i_pak2 and i_reject.
        block_proposal = self.nodes[i_pak1].getnewblockhex()
        assert_equal(
            self.nodes[i_novalidate].testproposedblock(block_proposal), None)
        assert_equal(self.nodes[i_undefined].testproposedblock(block_proposal),
                     None)
        assert_equal(self.nodes[i_pak1].testproposedblock(block_proposal),
                     None)

        assert_raises_rpc_error(
            -25, "Proposal PAK commitment and config PAK do not match.",
            self.nodes[i_pak2].testproposedblock, block_proposal)

        assert_raises_rpc_error(
            -25, "Proposal PAK commitment and config PAK do not match.",
            self.nodes[i_reject].testproposedblock, block_proposal)

        # Submit block with commitment to pak1 and check each node's state.
        self.nodes[i_undefined].submitblock(block_proposal)
        self.sync_all()
        test_pak(self.nodes[i_novalidate], pak1, pak1, False)
        test_pak(self.nodes[i_undefined], False, pak1, True)
        test_pak(self.nodes[i_pak1], pak1, pak1, True)
        test_pak(self.nodes[i_pak2], pak2, pak1, True)
        test_pak(self.nodes[i_reject], "reject", pak1, True)
        # Check that another block by i_pak1 (without a commitment) is valid to
        # i_pak1 but invalid to i_pak2 and i_reject
        block_proposal = self.nodes[i_undefined].getnewblockhex()
        assert_equal(
            self.nodes[i_novalidate].testproposedblock(block_proposal), None)
        assert_equal(self.nodes[i_undefined].testproposedblock(block_proposal),
                     None)
        assert_equal(self.nodes[i_pak1].testproposedblock(block_proposal),
                     None)

        assert_raises_rpc_error(
            -25, "Proposal does not have required PAK commitment.",
            self.nodes[i_pak2].testproposedblock, block_proposal)

        assert_raises_rpc_error(
            -25, "Proposal does not have required PAK commitment.",
            self.nodes[i_reject].testproposedblock, block_proposal)

        # PAK transition: pak1 -> reject
        # Create a new block with i_reject which should have a "reject" commitment
        # and check that it's correctly rejected or accepted.
        block_proposal = self.nodes[i_reject].getnewblockhex()
        assert_equal(
            self.nodes[i_novalidate].testproposedblock(block_proposal), None)
        assert_equal(self.nodes[i_undefined].testproposedblock(block_proposal),
                     None)

        assert_raises_rpc_error(
            -25, "Proposal PAK commitment and config PAK do not match.",
            self.nodes[i_pak1].testproposedblock, block_proposal)

        assert_equal(self.nodes[i_reject].testproposedblock(block_proposal),
                     None)
        # Submit "reject" block and check state.
        self.nodes[i_undefined].submitblock(block_proposal)
        self.sync_all()
        test_pak(self.nodes[i_novalidate], pak1, "reject", False)
        test_pak(self.nodes[i_undefined], False, "reject", True)
        test_pak(self.nodes[i_pak1], pak1, "reject", True)
        test_pak(self.nodes[i_pak2], pak2, "reject", True)
        test_pak(self.nodes[i_reject], "reject", "reject", True)
        # Check that another block by i_reject (without a commitment) is valid to i_reject.
        block_proposal = self.nodes[i_reject].getnewblockhex()
        assert_equal(self.nodes[i_reject].testproposedblock(block_proposal),
                     None)

        # Check that i_undefined can't peg-out because of the pegout freeze.
        assert_raises_rpc_error(-5, "Pegout freeze is under effect",
                                self.nodes[i_undefined].sendtomainchain, "", 1)

        assert_raises_rpc_error(
            -3,
            "`address` argument must be \"\" for PAK-enabled networks as the address is generated automatically.",
            self.nodes[i_undefined].sendtomainchain,
            "n3NkSZqoPMCQN5FENxUBw4qVATbytH6FDK", 1)

        # PAK transition: reject -> pak2
        # Restart nodes while putting pak2 in i_pak1's config instead of pak1.
        self.stop_nodes()
        extra_args = copy.deepcopy(args)
        extra_args[i_pak1] = extra_args[i_pak1] + pak_to_option(pak2)
        extra_args[i_pak2] = extra_args[i_pak2] + pak_to_option(pak2)
        # Also test novalidate behaves correctly when set to reject after removing
        # the two pak entries
        extra_args[i_novalidate] = extra_args[i_novalidate][:-2] + [
            '-pak=reject'
        ]

        # Restart and connect peers
        self.start_nodes(extra_args)
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 2, 3)
        connect_nodes_bi(self.nodes, 3, 4)

        # Check current state of i_pak1
        test_pak(self.nodes[i_pak1], pak2, "reject", True)
        # Create a new block with i_pak1 which should have a commitment to pak2
        # and check that it's correctly rejected or accepted.
        block_proposal = self.nodes[i_pak1].getnewblockhex()
        assert_equal(
            self.nodes[i_novalidate].testproposedblock(block_proposal), None)
        assert_equal(self.nodes[i_undefined].testproposedblock(block_proposal),
                     None)
        assert_equal(self.nodes[i_pak1].testproposedblock(block_proposal),
                     None)
        assert_equal(self.nodes[i_pak2].testproposedblock(block_proposal),
                     None)

        assert_raises_rpc_error(
            -25, "Proposal PAK commitment and config PAK do not match.",
            self.nodes[i_reject].testproposedblock, block_proposal)

        # Submit block with commitment to pak2 and check state.
        self.nodes[i_pak1].submitblock(block_proposal)
        self.sync_all()
        test_pak(self.nodes[i_novalidate], "reject", pak2, False)
        test_pak(self.nodes[i_undefined], False, pak2, True)
        test_pak(self.nodes[i_pak1], pak2, pak2, True)
        test_pak(self.nodes[i_pak2], pak2, pak2, True)
        test_pak(self.nodes[i_reject], "reject", pak2, True)

        # Reset PAK conf arguments to start to test mempool acceptance and wallet

        # We will re-use the same xpub, but each wallet will create its own online pak
        # so the lists will be incompatible, even if all else was synced
        xpub = "tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B"
        xpub_desc = "pkh(" + xpub + "/0/*)"  # Transform this into a descriptor
        init_results = []
        info_results = []
        for i in range(5):
            if i == 0:
                assert_raises_rpc_error(
                    -8, "PAK enforcement is not enabled on this network.",
                    self.nodes[i].initpegoutwallet, xpub)
                init_results += [None]
                info_results += [None]
                continue

            init_results += [self.nodes[i].initpegoutwallet(xpub)]
            info_results += [self.nodes[i].getwalletpakinfo()]
            assert_equal(init_results[i]["address_lookahead"],
                         info_results[i]["address_lookahead"])
            assert_equal(init_results[i]["liquid_pak"],
                         info_results[i]["liquid_pak"])
            assert_equal(init_results[i]["liquid_pak_address"],
                         info_results[i]["liquid_pak_address"])
            assert_equal(info_results[i]["bitcoin_descriptor"], xpub_desc)
            assert_equal(info_results[i]["bip32_counter"], "0")

        # Use custom derivation counter values, check if stored correctly,
        # address lookahead looks correct and that new liquid_pak was chosen
        assert_raises_rpc_error(
            -8,
            "bip32_counter must be between 0 and 1,000,000,000, inclusive.",
            self.nodes[i_undefined].initpegoutwallet, xpub, -1)

        assert_raises_rpc_error(
            -8,
            "bip32_counter must be between 0 and 1,000,000,000, inclusive.",
            self.nodes[i_undefined].initpegoutwallet, xpub, 1000000001)

        new_init = self.nodes[i_undefined].initpegoutwallet(xpub, 2)
        assert_equal(
            self.nodes[i_undefined].getwalletpakinfo()["bip32_counter"], "2")
        assert_equal(new_init["address_lookahead"][0],
                     init_results[i_undefined]["address_lookahead"][2])
        assert (new_init["liquid_pak"] !=
                init_results[i_undefined]["liquid_pak"])

        # Load additional pak entry for each, restart (reject node disallows pak list in conf)
        # By adding different pak entries, all nodes that validate the list should conflict
        self.stop_nodes()
        extra_args = copy.deepcopy(args)
        extra_args[i_pak1] = extra_args[i_pak1] + [
            "-" + init_results[i_pak1]["pakentry"]
        ]
        extra_args[i_pak2] = extra_args[i_pak2] + [
            "-" + init_results[i_pak2]["pakentry"]
        ]

        # Restart and connect peers
        self.start_nodes(extra_args)
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 2, 3)
        connect_nodes_bi(self.nodes, 3, 4)

        # Check PAK settings persistence in wallet across restart
        restarted_info = self.nodes[i_undefined].getwalletpakinfo()
        assert_equal(restarted_info["bitcoin_descriptor"], xpub_desc)
        assert_equal(restarted_info["liquid_pak"], new_init["liquid_pak"])
        assert_equal(restarted_info["bip32_counter"], "2")

        # Have nodes send pegouts, check it fails to enter mempool of other nodes with incompatible
        # PAK settings
        self.nodes[i_novalidate].sendmany(
            "", {
                self.nodes[i_undefined].getnewaddress(): 10,
                self.nodes[i_pak1].getnewaddress(): 10,
                self.nodes[i_pak2].getnewaddress(): 10,
                self.nodes[i_reject].getnewaddress(): 10
            })
        self.nodes[i_novalidate].generate(1)
        self.sync_all()

        # pak1 generates a block, creating block commitment
        self.nodes[i_pak1].generate(1)
        self.sync_all()

        # pak1 will now create a pegout.
        pak1_pegout_txid = self.nodes[i_pak1].sendtomainchain("", 1)["txid"]
        assert_equal(self.nodes[i_pak1].getwalletpakinfo()["bip32_counter"],
                     "1")
        # Also spend the change to make chained payment that will be rejected as well
        pak1_child_txid = self.nodes[i_pak1].sendtoaddress(
            self.nodes[i_pak1].getnewaddress(),
            self.nodes[i_pak1].getbalance()['bitcoin'], "", "", True)

        # Wait for node("follow the leader" conf-undefined) to get transaction in
        time_to_wait = 15
        while time_to_wait > 0:
            # novalidate doesn't allow >80 byte op_return outputs due to no enforce_pak
            if (pak1_pegout_txid
                    not in self.nodes[i_novalidate].getrawmempool()
                    and pak1_pegout_txid
                    in self.nodes[i_undefined].getrawmempool() and
                    pak1_pegout_txid not in self.nodes[i_pak2].getrawmempool()
                    and pak1_pegout_txid
                    not in self.nodes[i_reject].getrawmempool()):
                break
            time_to_wait -= 1
            time.sleep(1)
        assert (time_to_wait > 0)

        # pak_reject will make a block commitment, causing all validating nodes to dump
        # the peg transaction
        self.nodes[i_reject].generate(1)
        sync_blocks(self.nodes)

        assert_equal(
            pak1_pegout_txid in self.nodes[i_novalidate].getrawmempool(),
            False)
        assert_equal(
            pak1_pegout_txid in self.nodes[i_undefined].getrawmempool(), False)
        assert_equal(pak1_pegout_txid in self.nodes[i_pak1].getrawmempool(),
                     True)
        assert_equal(pak1_pegout_txid in self.nodes[i_pak2].getrawmempool(),
                     False)
        assert_equal(pak1_pegout_txid in self.nodes[i_reject].getrawmempool(),
                     False)

        assert_equal(
            self.nodes[i_pak1].gettransaction(pak1_pegout_txid)
            ["confirmations"], 0)

        # Make sure child payment also bumped from mempool
        assert_equal(
            pak1_child_txid in self.nodes[i_novalidate].getrawmempool(), False)
        assert_equal(
            pak1_child_txid in self.nodes[i_undefined].getrawmempool(), False)
        assert_equal(pak1_child_txid in self.nodes[i_pak1].getrawmempool(),
                     True)
        assert_equal(pak1_child_txid in self.nodes[i_pak2].getrawmempool(),
                     False)
        assert_equal(pak1_child_txid in self.nodes[i_reject].getrawmempool(),
                     False)

        assert_equal(
            self.nodes[i_pak1].gettransaction(pak1_child_txid)
            ["confirmations"], 0)
        # Fail to peg-out too-small value
        assert_raises_rpc_error(
            -8, "Invalid amount for send, must send more than 0.0001 BTC",
            self.nodes[i_undefined].sendtomainchain, "", Decimal('0.0009'))

        # Use wrong network's extended pubkey
        mainnetxpub = "xpub6AATBi58516uxLogbuaG3jkom7x1qyDoZzMN2AePBuQnMFKUV9xC2BW9vXsFJ9rELsvbeGQcFWhtbyM4qDeijM22u3AaSiSYEvuMZkJqtLn"
        assert_raises_rpc_error(
            -8, "bitcoin_descriptor is not a valid descriptor string.",
            self.nodes[i_undefined].initpegoutwallet, mainnetxpub)

        # Test fixed online pubkey
        init_info = self.nodes[i_pak1].initpegoutwallet(xpub)
        init_info2 = self.nodes[i_pak1].initpegoutwallet(
            xpub, 0, init_info['liquid_pak'])
        assert_equal(init_info, init_info2)
        init_info3 = self.nodes[i_pak1].initpegoutwallet(xpub)
        assert (init_info != init_info3)

        # Test Descriptor PAK Support

        # Non-supported descriptors
        assert_raises_rpc_error(
            -8,
            "bitcoin_descriptor is not of any type supported: pkh(<xpub>), sh(wpkh(<xpub>)), wpkh(<xpub>), or <xpub>.",
            self.nodes[i_pak1].initpegoutwallet,
            "pk(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/0/*)"
        )

        assert_raises_rpc_error(
            -8, "bitcoin_descriptor must be a ranged descriptor.",
            self.nodes[i_pak1].initpegoutwallet,
            "pkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B)"
        )

        # key origins aren't supported in 0.17
        assert_raises_rpc_error(
            -8, "bitcoin_descriptor is not a valid descriptor string.",
            self.nodes[i_pak1].initpegoutwallet,
            "pkh([d34db33f/44'/0'/0']tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/*)"
        )

        # Peg out with each new type, check that destination script matches
        wpkh_desc = "wpkh(" + xpub + "/0/*)"
        wpkh_info = self.nodes[i_pak1].initpegoutwallet(wpkh_desc)
        wpkh_pak_info = self.nodes[i_pak1].getwalletpakinfo()

        # Add to pak list for pak1, restart
        self.stop_nodes()
        extra_args = copy.deepcopy(args)
        extra_args[i_pak1] = extra_args[i_pak1] + ["-" + wpkh_info["pakentry"]]
        self.start_nodes(extra_args)

        # Make block commitment and get some block subsidy
        self.nodes[i_pak1].generate(101)
        wpkh_stmc = self.nodes[i_pak1].sendtomainchain("", 1)
        wpkh_txid = wpkh_stmc['txid']

        # Also check some basic return fields of sendtomainchain with pak
        assert_equal(wpkh_stmc["bitcoin_address"],
                     wpkh_info["address_lookahead"][0])
        validata = self.nodes[i_pak1].validateaddress(
            wpkh_stmc["bitcoin_address"])
        assert (not validata["isvalid"])
        assert (validata["isvalid_parent"])
        assert_equal(wpkh_pak_info["bip32_counter"],
                     wpkh_stmc["bip32_counter"])
        assert_equal(wpkh_pak_info["bitcoin_descriptor"],
                     wpkh_stmc["bitcoin_descriptor"])

        sh_wpkh_desc = "sh(wpkh(" + xpub + "/0/1/*))"
        sh_wpkh_info = self.nodes[i_pak1].initpegoutwallet(sh_wpkh_desc)

        # Add to pak list for pak1, restart
        self.stop_nodes()
        extra_args = copy.deepcopy(args)
        extra_args[i_pak1] = extra_args[i_pak1] + [
            "-" + sh_wpkh_info["pakentry"]
        ]

        # Restart and connect peers
        self.start_nodes(extra_args)
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 2, 3)
        connect_nodes_bi(self.nodes, 3, 4)

        self.nodes[i_pak1].generate(1)
        sh_wpkh_txid = self.nodes[i_pak1].sendtomainchain("", 1)['txid']

        # Make sure peg-outs look correct
        wpkh_raw = self.nodes[i_pak1].decoderawtransaction(
            self.nodes[i_pak1].gettransaction(wpkh_txid)['hex'])
        sh_wpkh_raw = self.nodes[i_pak1].decoderawtransaction(
            self.nodes[i_pak1].gettransaction(sh_wpkh_txid)['hex'])

        peg_out_found = False
        for output in wpkh_raw["vout"]:
            if "pegout_addresses" in output["scriptPubKey"]:
                if output["scriptPubKey"]["pegout_addresses"][0] \
                        == wpkh_info["address_lookahead"][0]:
                    peg_out_found = True
                    break
                else:
                    raise Exception("Found unexpected peg-out output")
        assert (peg_out_found)

        peg_out_found = False
        for output in sh_wpkh_raw["vout"]:
            if "pegout_addresses" in output["scriptPubKey"]:
                if output["scriptPubKey"]["pegout_addresses"][0] \
                        == sh_wpkh_info["address_lookahead"][0]:
                    peg_out_found = True
                    break
                else:
                    raise Exception("Found unexpected peg-out output")
        assert (peg_out_found)
    def run_test(self):

        # Transitioning PAK lists and checking lists in RPC tested in feature_dynafed

        self.log.info("Test wallet PAK")

        # We will re-use the same xpub, but each wallet will create its own online pak
        # so the lists will be incompatible, even if all else was synced
        xpub = "tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B"
        xpub_desc = "pkh(" + xpub + "/0/*)"  # Transform this into a descriptor
        init_results = []
        info_results = []
        for i in range(self.num_nodes):
            if i == 0:
                assert_raises_rpc_error(
                    -8, "PAK enforcement is not enabled on this network.",
                    self.nodes[i].initpegoutwallet, xpub)
                init_results += [None]
                info_results += [None]
                continue

            init_results += [self.nodes[i].initpegoutwallet(xpub)]
            info_results += [self.nodes[i].getwalletpakinfo()]
            assert_equal(init_results[i]["address_lookahead"],
                         info_results[i]["address_lookahead"])
            assert_equal(init_results[i]["liquid_pak"],
                         info_results[i]["liquid_pak"])
            assert_equal(init_results[i]["liquid_pak_address"],
                         info_results[i]["liquid_pak_address"])
            assert_equal(info_results[i]["bitcoin_descriptor"], xpub_desc)
            assert_equal(info_results[i]["bip32_counter"], "0")
            validata = self.nodes[i].validateaddress(
                init_results[i]["address_lookahead"][0])
            assert not validata["isvalid"]
            assert validata["isvalid_parent"]
            assert not validata["parent_address_info"]["isscript"]
            assert not validata["parent_address_info"]["iswitness"]

        # Use custom derivation counter values, check if stored correctly,
        # address lookahead looks correct and that new liquid_pak was chosen
        assert_raises_rpc_error(
            -8,
            "bip32_counter must be between 0 and 1,000,000,000, inclusive.",
            self.nodes[1].initpegoutwallet, xpub, -1)

        assert_raises_rpc_error(
            -8,
            "bip32_counter must be between 0 and 1,000,000,000, inclusive.",
            self.nodes[1].initpegoutwallet, xpub, 1000000001)

        # Make sure we can also prepend the key origin to the xpub.
        self.nodes[1].initpegoutwallet("pkh([deadbeef/44h/0h/0h]" + xpub +
                                       "/0/*)")
        new_init = self.nodes[1].initpegoutwallet(xpub, 2)
        assert_equal(self.nodes[1].getwalletpakinfo()["bip32_counter"], "2")
        assert_equal(new_init["address_lookahead"][0],
                     init_results[1]["address_lookahead"][2])
        assert (new_init["liquid_pak"] != init_results[1]["liquid_pak"])

        # Restart and connect peers to check wallet persistence
        self.stop_nodes()
        self.start_nodes()
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)

        # Check PAK settings persistence in wallet across restart
        restarted_info = self.nodes[1].getwalletpakinfo()
        assert_equal(restarted_info["bitcoin_descriptor"], xpub_desc)
        assert_equal(restarted_info["liquid_pak"], new_init["liquid_pak"])
        assert_equal(restarted_info["bip32_counter"], "2")

        # Compile list of extension space entries for pak enforcement
        extension_space_proposal = []
        for entry in init_results:
            if entry is not None:
                pakentry = entry["pakentry"]
                extension_space_proposal += [
                    pakentry[4:4 + 66] + pakentry[4 + 66 + 1:]
                ]

        self.log.info("Test mempool enforcement of PAK peg-outs")

        # Transition to a pak list that only node 1 can peg-out to
        WSH_OP_TRUE = self.nodes[0].decodescript("51")["segwit"]["hex"]
        for _ in range(9):
            block = self.nodes[1].getnewblockhex(
                0, {
                    "signblockscript": WSH_OP_TRUE,
                    "max_block_witness": 3,
                    "fedpegscript": "51",
                    "extension_space": [extension_space_proposal[0]]
                })
            assert_equal(self.nodes[1].submitblock(block), None)

        self.sync_all()
        assert_equal(self.nodes[0].getblockchaininfo()["extension_space"],
                     [extension_space_proposal[0]])

        # node 1 has wrong pak entry in wallet
        assert_raises_rpc_error(
            -4, "Given online key is not in Pegout Authorization Key List",
            self.nodes[1].sendtomainchain, "", 1)

        # put back init_info version that's in pak list
        self.nodes[1].initpegoutwallet(xpub, 0, init_results[1]["liquid_pak"])

        # Node 1 will now make a PAK peg-out, accepted in all mempools and blocks
        pegout_info = self.nodes[1].sendtomainchain("", 1)
        raw_node1_pegout = self.nodes[1].gettransaction(
            pegout_info["txid"])["hex"]
        self.sync_all()  # mempool sync
        self.nodes[1].generatetoaddress(1, self.nodes[0].getnewaddress())
        self.sync_all()  # block sync
        assert_greater_than(
            self.nodes[1].gettransaction(pegout_info["txid"])["confirmations"],
            0)

        # Re-org keep node 1 peg-out unconfirmed and transition to "full list"
        # then check peg-out fails

        # Invalidate back to block 1, then make 9 new blocks to hit transition
        # If you roll back to genesis block p2p code gets flakey
        num_block_rollback = self.nodes[1].getblockcount() - 2
        fork_hash = self.nodes[1].getblockhash(2)
        for i in range(self.num_nodes):
            self.nodes[i].invalidateblock(fork_hash)
        sync_blocks(self.nodes)

        for _ in range(num_block_rollback):
            block = self.nodes[1].getnewblockhex(
                0, {
                    "signblockscript": WSH_OP_TRUE,
                    "max_block_witness": 3,
                    "fedpegscript": "51",
                    "extension_space": extension_space_proposal
                })
            self.nodes[1].submitblock(block)

        sync_blocks(self.nodes)

        # node 0 puts the peg-out back in its mempool, can't sync all
        self.nodes[0].sendrawtransaction(raw_node1_pegout)
        sync_mempools(self.nodes[1:])

        # rejected in mempool
        assert_raises_rpc_error(-26, "invalid-pegout-proof",
                                self.nodes[1].sendrawtransaction,
                                raw_node1_pegout)
        assert_raises_rpc_error(-26, "invalid-pegout-proof",
                                self.nodes[2].sendrawtransaction,
                                raw_node1_pegout)
        # node 0 tries to make bad block
        wrong_pak_prop = self.nodes[0].getnewblockhex()
        # rejected in blocks
        assert_raises_rpc_error(-25, "bad-pak-tx",
                                self.nodes[1].testproposedblock,
                                wrong_pak_prop, True)
        assert_raises_rpc_error(-25, "bad-pak-tx",
                                self.nodes[2].testproposedblock,
                                wrong_pak_prop, True)

        self.log.info("Test various RPC arguments")

        # Fail to peg-out too-small value
        assert_raises_rpc_error(
            -8, "Invalid amount for send, must send more than 0.00100000 BTC",
            self.nodes[1].sendtomainchain, "", Decimal('0.0009'))

        # Use wrong network's extended pubkey
        mainnetxpub = "xpub6AATBi58516uxLogbuaG3jkom7x1qyDoZzMN2AePBuQnMFKUV9xC2BW9vXsFJ9rELsvbeGQcFWhtbyM4qDeijM22u3AaSiSYEvuMZkJqtLn"
        assert_raises_rpc_error(
            -8, "bitcoin_descriptor is not a valid descriptor string.",
            self.nodes[1].initpegoutwallet, mainnetxpub)

        # Test fixed online pubkey
        init_info = self.nodes[1].initpegoutwallet(xpub)
        init_info2 = self.nodes[1].initpegoutwallet(xpub, 0,
                                                    init_info['liquid_pak'])
        assert_equal(init_info, init_info2)
        init_info3 = self.nodes[1].initpegoutwallet(xpub)
        assert (init_info != init_info3)

        # Test Descriptor PAK Support

        # Non-supported descriptors
        assert_raises_rpc_error(
            -8,
            "bitcoin_descriptor is not of any type supported: pkh(<xpub>), sh(wpkh(<xpub>)), wpkh(<xpub>), or <xpub>.",
            self.nodes[1].initpegoutwallet,
            "pk(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/0/*)"
        )

        assert_raises_rpc_error(
            -8, "bitcoin_descriptor must be a ranged descriptor.",
            self.nodes[1].initpegoutwallet,
            "pkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B)"
        )

        # Peg out with each new type, check that destination script matches
        wpkh_desc = "wpkh(" + xpub + "/0/*)"
        # add a valid checksum
        wpkh_desc = self.nodes[1].getdescriptorinfo(wpkh_desc)["descriptor"]
        wpkh_info = self.nodes[1].initpegoutwallet(wpkh_desc)
        wpkh_pak_info = self.nodes[1].getwalletpakinfo()

        # Transition to wpkh entry list
        wpkh_pak_entry = wpkh_info["pakentry"]
        wpkh_pak_prop = [
            wpkh_pak_entry[4:4 + 66] + wpkh_pak_entry[4 + 66 + 1:]
        ]
        for _ in range(10):
            block = self.nodes[1].getnewblockhex(
                0, {
                    "signblockscript": WSH_OP_TRUE,
                    "max_block_witness": 3,
                    "fedpegscript": "51",
                    "extension_space": wpkh_pak_prop
                })
            self.nodes[1].submitblock(block)
        sync_blocks(self.nodes)

        # Get some block subsidy and send off
        self.nodes[1].generatetoaddress(101, self.nodes[1].getnewaddress())
        wpkh_stmc = self.nodes[1].sendtomainchain("", 1)
        wpkh_txid = wpkh_stmc['txid']

        # Also check some basic return fields of sendtomainchain with pak
        assert_equal(wpkh_stmc["bitcoin_address"],
                     wpkh_info["address_lookahead"][0])
        validata = self.nodes[1].validateaddress(wpkh_stmc["bitcoin_address"])
        assert (not validata["isvalid"])
        assert (validata["isvalid_parent"])
        assert (not validata["parent_address_info"]["isscript"])
        assert (validata["parent_address_info"]["iswitness"])
        assert_equal(wpkh_pak_info["bip32_counter"],
                     wpkh_stmc["bip32_counter"])
        assert_equal(wpkh_pak_info["bitcoin_descriptor"],
                     wpkh_stmc["bitcoin_descriptor"])

        sh_wpkh_desc = "sh(wpkh(" + xpub + "/0/1/*))"
        sh_wpkh_info = self.nodes[1].initpegoutwallet(sh_wpkh_desc)

        validata = self.nodes[1].validateaddress(
            sh_wpkh_info["address_lookahead"][0])
        assert (not validata["isvalid"])
        assert (validata["isvalid_parent"])
        assert (validata["parent_address_info"]["isscript"])
        assert (not validata["parent_address_info"]["iswitness"])

        # Transition to sh_wpkh entry list
        sh_wpkh_pak_entry = sh_wpkh_info["pakentry"]
        sh_wpkh_pak_prop = [
            sh_wpkh_pak_entry[4:4 + 66] + sh_wpkh_pak_entry[4 + 66 + 1:]
        ]
        for _ in range(10):
            block = self.nodes[1].getnewblockhex(
                0, {
                    "signblockscript": WSH_OP_TRUE,
                    "max_block_witness": 3,
                    "fedpegscript": "51",
                    "extension_space": sh_wpkh_pak_prop
                })
            self.nodes[1].submitblock(block)
        sync_blocks(self.nodes)

        self.nodes[1].generatetoaddress(1, self.nodes[1].getnewaddress())
        sh_wpkh_txid = self.nodes[1].sendtomainchain("", 1)['txid']

        # Make sure peg-outs look correct
        wpkh_raw = self.nodes[1].decoderawtransaction(
            self.nodes[1].gettransaction(wpkh_txid)['hex'])
        sh_wpkh_raw = self.nodes[1].decoderawtransaction(
            self.nodes[1].gettransaction(sh_wpkh_txid)['hex'])

        peg_out_found = False
        for output in wpkh_raw["vout"]:
            if "pegout_addresses" in output["scriptPubKey"]:
                if output["scriptPubKey"]["pegout_addresses"][0] \
                        == wpkh_info["address_lookahead"][0]:
                    peg_out_found = True
                    break
                else:
                    raise Exception("Found unexpected peg-out output")
        assert (peg_out_found)

        peg_out_found = False
        for output in sh_wpkh_raw["vout"]:
            if "pegout_addresses" in output["scriptPubKey"]:
                if output["scriptPubKey"]["pegout_addresses"][0] \
                        == sh_wpkh_info["address_lookahead"][0]:
                    peg_out_found = True
                    break
                else:
                    raise Exception("Found unexpected peg-out output")
        assert (peg_out_found)

        # Make sure they all confirm
        self.nodes[1].generatetoaddress(1, self.nodes[0].getnewaddress())
        for tx_id in [wpkh_txid, sh_wpkh_txid]:
            assert_greater_than(
                self.nodes[1].gettransaction(tx_id)["confirmations"], 0)

        self.log.info("Test that pak-less pegouts are rejected")

        # Last test of a pak-less peg-out failing to get into mempool/block
        # Note it leaves a transaction in node 0's mempool, so sync_all cannot
        # work after unless it's somehow booted.

        # node 0 will now create a pegout, will fail to enter mempool of node 1 or 2
        # since it's pak-less
        nopak_pegout_txid = self.nodes[0].sendtomainchain(
            "n3NkSZqoPMCQN5FENxUBw4qVATbytH6FDK", 1)
        raw_pakless_pegout = self.nodes[0].gettransaction(
            nopak_pegout_txid)["hex"]
        assert nopak_pegout_txid in self.nodes[0].getrawmempool()

        assert_raises_rpc_error(-26, "invalid-pegout-proof",
                                self.nodes[1].sendrawtransaction,
                                raw_pakless_pegout)
        assert_raises_rpc_error(-26, "invalid-pegout-proof",
                                self.nodes[2].sendrawtransaction,
                                raw_pakless_pegout)

        # node 0 makes a block that includes the pakless pegout, rejected by others
        # by consensus
        bad_prop = self.nodes[0].getnewblockhex()
        assert_raises_rpc_error(-25, "bad-pak-tx",
                                self.nodes[1].testproposedblock, bad_prop,
                                True)
        assert_raises_rpc_error(-25, "bad-pak-tx",
                                self.nodes[2].testproposedblock, bad_prop,
                                True)

        # Test that subtracting fee from output works
        self.nodes[1].generatetoaddress(101, self.nodes[1].getnewaddress())
        self.nodes[1].sendtomainchain("",
                                      self.nodes[1].getbalance()["bitcoin"],
                                      True)
        assert_equal(self.nodes[1].getbalance()["bitcoin"], 0)
Beispiel #12
0
    def run_test(self):
        url = urllib.parse.urlparse(self.nodes[0].url)
        self.log.info("Mining blocks...")

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

        assert_equal(self.nodes[0].getbalance(), 5000)

        txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        bb_hash = self.nodes[0].getbestblockhash()

        assert_equal(self.nodes[1].getbalance(), Decimal("0.1")) #balance now should be 0.1 on node 1

        # load the latest 0.1 tx over the REST API
        json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+txid+self.FORMAT_SEPARATOR+"json")
        json_obj = json.loads(json_string)
        vintx = json_obj['vin'][0]['txid'] # get the vin to later check for utxo (should be spent by then)
        # get n of 0.1 outpoint
        n = 0
        for vout in json_obj['vout']:
            if vout['value'] == 0.1:
                n = vout['n']


        #######################################
        # GETUTXOS: query an unspent outpoint #
        #######################################
        json_request = '/checkmempool/'+txid+'-'+str(n)
        json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
        json_obj = json.loads(json_string)

        #check chainTip response
        assert_equal(json_obj['chaintipHash'], bb_hash)

        #make sure there is one utxo
        assert_equal(len(json_obj['utxos']), 1)
        assert_equal(json_obj['utxos'][0]['value'], 0.1)


        #################################################
        # GETUTXOS: now query an already spent outpoint #
        #################################################
        json_request = '/checkmempool/'+vintx+'-0'
        json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
        json_obj = json.loads(json_string)

        #check chainTip response
        assert_equal(json_obj['chaintipHash'], bb_hash)

        # make sure there is no utxo in the response because this oupoint has been spent
        assert_equal(len(json_obj['utxos']), 0)

        #check bitmap
        assert_equal(json_obj['bitmap'], "0")


        ##################################################
        # GETUTXOS: now check both with the same request #
        ##################################################
        json_request = '/checkmempool/'+txid+'-'+str(n)+'/'+vintx+'-0'
        json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
        json_obj = json.loads(json_string)
        assert_equal(len(json_obj['utxos']), 1)
        assert_equal(json_obj['bitmap'], "10")

        #test binary response
        bb_hash = self.nodes[0].getbestblockhash()

        binaryRequest = b'\x01\x02'
        binaryRequest += hex_str_to_bytes(txid)
        binaryRequest += pack("i", n)
        binaryRequest += hex_str_to_bytes(vintx)
        binaryRequest += pack("i", 0)

        bin_response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'bin', binaryRequest)
        output = BytesIO()
        output.write(bin_response)
        output.seek(0)
        chainHeight = unpack("i", output.read(4))[0]
        hashFromBinResponse = hex(deser_uint256(output))[2:].zfill(64)

        assert_equal(bb_hash, hashFromBinResponse) #check if getutxo's chaintip during calculation was fine
        assert_equal(chainHeight, 102) #chain height must be 102


        ############################
        # GETUTXOS: mempool checks #
        ############################

        # do a tx and don't sync
        txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)
        json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+txid+self.FORMAT_SEPARATOR+"json")
        json_obj = json.loads(json_string)
        #vintx = json_obj['vin'][0]['txid'] # get the vin to later check for utxo (should be spent by then)
        # get n of 0.1 outpoint
        n = 0
        for vout in json_obj['vout']:
            if vout['value'] == 0.1:
                n = vout['n']

        json_request = '/'+txid+'-'+str(n)
        json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
        json_obj = json.loads(json_string)
        assert_equal(len(json_obj['utxos']), 0) #there should be an outpoint because it has just added to the mempool

        json_request = '/checkmempool/'+txid+'-'+str(n)
        json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
        json_obj = json.loads(json_string)
        assert_equal(len(json_obj['utxos']), 1) #there should be an outpoint because it has just added to the mempool

        #do some invalid requests
        json_request = '{"checkmempool'
        response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'json', json_request, True)
        assert_equal(response.status, 400) #must be a 400 because we send an invalid json request

        json_request = '{"checkmempool'
        response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'bin', json_request, True)
        assert_equal(response.status, 400) #must be a 400 because we send an invalid bin request

        response = http_post_call(url.hostname, url.port, '/rest/getutxos/checkmempool'+self.FORMAT_SEPARATOR+'bin', '', True)
        assert_equal(response.status, 400) #must be a 400 because we send an invalid bin request

        #test limits
        json_request = '/checkmempool/'
        for _ in range(0, 20):
            json_request += txid+'-'+str(n)+'/'
        json_request = json_request.rstrip("/")
        response = http_post_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True)
        assert_equal(response.status, 400) #must be a 400 because we exceeding the limits

        json_request = '/checkmempool/'
        for _ in range(0, 15):
            json_request += txid+'-'+str(n)+'/'
        json_request = json_request.rstrip("/")
        response = http_post_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True)
        assert_equal(response.status, 200) #must be a 200 because we are within the limits

        self.nodes[0].generate(1) #generate block to not affect upcoming tests
        self.sync_all()

        ################
        # /rest/block/ #
        ################

        # check binary format
        response = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+"bin", True)
        assert_equal(response.status, 200)
        assert_greater_than(int(response.getheader('content-length')), 80)
        response_str = response.read()

        # compare with block header
        response_header = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"bin", True)
        assert_equal(response_header.status, 200)
        assert_equal(int(response_header.getheader('content-length')), 80)
        response_header_str = response_header.read()
        assert_equal(response_str[0:80], response_header_str)

        # check block hex format
        response_hex = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+"hex", True)
        assert_equal(response_hex.status, 200)
        assert_greater_than(int(response_hex.getheader('content-length')), 160)
        response_hex_str = response_hex.read()
        assert_equal(encode(response_str, "hex_codec")[0:160], response_hex_str[0:160])

        # compare with hex block header
        response_header_hex = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"hex", True)
        assert_equal(response_header_hex.status, 200)
        assert_greater_than(int(response_header_hex.getheader('content-length')), 160)
        response_header_hex_str = response_header_hex.read()
        assert_equal(response_hex_str[0:160], response_header_hex_str[0:160])
        assert_equal(encode(response_header_str, "hex_codec")[0:160], response_header_hex_str[0:160])

        # check json format
        block_json_string = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+'json')
        block_json_obj = json.loads(block_json_string)
        assert_equal(block_json_obj['hash'], bb_hash)

        # compare with json block header
        response_header_json = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"json", True)
        assert_equal(response_header_json.status, 200)
        response_header_json_str = response_header_json.read().decode('utf-8')
        json_obj = json.loads(response_header_json_str, parse_float=Decimal)
        assert_equal(len(json_obj), 1) #ensure that there is one header in the json response
        assert_equal(json_obj[0]['hash'], bb_hash) #request/response hash should be the same

        #compare with normal RPC block response
        rpc_block_json = self.nodes[0].getblock(bb_hash)
        assert_equal(json_obj[0]['hash'],               rpc_block_json['hash'])
        assert_equal(json_obj[0]['confirmations'],      rpc_block_json['confirmations'])
        assert_equal(json_obj[0]['height'],             rpc_block_json['height'])
        assert_equal(json_obj[0]['version'],            rpc_block_json['version'])
        assert_equal(json_obj[0]['merkleroot'],         rpc_block_json['merkleroot'])
        assert_equal(json_obj[0]['time'],               rpc_block_json['time'])
        assert_equal(json_obj[0]['nonce'],              rpc_block_json['nonce'])
        assert_equal(json_obj[0]['bits'],               rpc_block_json['bits'])
        assert_equal(json_obj[0]['difficulty'],         rpc_block_json['difficulty'])
        assert_equal(json_obj[0]['chainwork'],          rpc_block_json['chainwork'])
        assert_equal(json_obj[0]['previousblockhash'],  rpc_block_json['previousblockhash'])

        #see if we can get 5 headers in one response
        self.nodes[1].generate(5)
        self.sync_all()
        response_header_json = http_get_call(url.hostname, url.port, '/rest/headers/5/'+bb_hash+self.FORMAT_SEPARATOR+"json", True)
        assert_equal(response_header_json.status, 200)
        response_header_json_str = response_header_json.read().decode('utf-8')
        json_obj = json.loads(response_header_json_str)
        assert_equal(len(json_obj), 5) #now we should have 5 header objects

        # do tx test
        tx_hash = block_json_obj['tx'][0]['txid']
        json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"json")
        json_obj = json.loads(json_string)
        assert_equal(json_obj['txid'], tx_hash)

        # check hex format response
        hex_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"hex", True)
        assert_equal(hex_string.status, 200)
        assert_greater_than(int(response.getheader('content-length')), 10)


        # check block tx details
        # let's make 3 tx and mine them on node 1
        txs = [self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11),
               self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11),
               self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)]
        self.sync_all()

        # check that there are exactly 3 transactions in the TX memory pool before generating the block
        json_string = http_get_call(url.hostname, url.port, '/rest/mempool/info'+self.FORMAT_SEPARATOR+'json')
        json_obj = json.loads(json_string)
        assert_equal(json_obj['size'], 3)
        # the size of the memory pool should be greater than 3x ~100 bytes
        assert_greater_than(json_obj['bytes'], 300)

        # check that there are our submitted transactions in the TX memory pool
        json_string = http_get_call(url.hostname, url.port, '/rest/mempool/contents'+self.FORMAT_SEPARATOR+'json')
        json_obj = json.loads(json_string)
        for tx in txs:
            assert_equal(tx in json_obj, True)

        # now mine the transactions
        newblockhash = self.nodes[1].generate(1)
        self.sync_all()

        #check if the 3 tx show up in the new block
        json_string = http_get_call(url.hostname, url.port, '/rest/block/'+newblockhash[0]+self.FORMAT_SEPARATOR+'json')
        json_obj = json.loads(json_string)
        for tx in json_obj['tx']:
            if not 'coinbase' in tx['vin'][0]: #exclude coinbase
                assert_equal(tx['txid'] in txs, True)

        #check the same but without tx details
        json_string = http_get_call(url.hostname, url.port, '/rest/block/notxdetails/'+newblockhash[0]+self.FORMAT_SEPARATOR+'json')
        json_obj = json.loads(json_string)
        for tx in txs:
            assert_equal(tx in json_obj['tx'], True)

        #test rest bestblock
        bb_hash = self.nodes[0].getbestblockhash()

        json_string = http_get_call(url.hostname, url.port, '/rest/chaininfo.json')
        json_obj = json.loads(json_string)
        assert_equal(json_obj['bestblockhash'], bb_hash)
Beispiel #13
0
    def run_test(self):
        # All nodes should start with 125,000 RVN:
        starting_balance = 125000
        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!

        # Assign coins to foo and bar accounts:
        node0_address_foo = self.nodes[0].getnewaddress("foo")
        fund_foo_txid = self.nodes[0].sendfrom("", node0_address_foo, 121900)
        fund_foo_tx = self.nodes[0].gettransaction(fund_foo_txid)

        node0_address_bar = self.nodes[0].getnewaddress("bar")
        fund_bar_txid = self.nodes[0].sendfrom("", node0_address_bar, 2900)
        fund_bar_tx = self.nodes[0].gettransaction(fund_bar_txid)

        assert_equal(
            self.nodes[0].getbalance(""), starting_balance - 121900 - 2900 +
            fund_foo_tx["fee"] + fund_bar_tx["fee"])

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

        # First: use raw transaction API to send 1240 RVN to node1_address,
        # but don't broadcast:
        doublespend_fee = Decimal('-.02')
        rawtx_input_0 = {
            "txid": fund_foo_txid,
            "vout": find_output(self.nodes[0], fund_foo_txid, 121900)
        }
        rawtx_input_1 = {
            "txid": fund_bar_txid,
            "vout": find_output(self.nodes[0], fund_bar_txid, 2900)
        }
        inputs = [rawtx_input_0, rawtx_input_1]
        change_address = self.nodes[0].getnewaddress()
        outputs = {
            node1_address: 124000,
            change_address: 124800 - 124000 + doublespend_fee
        }
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        doublespend = self.nodes[0].signrawtransaction(rawtx)
        assert_equal(doublespend["complete"], True)

        # Create two spends using 1 50 RVN coin each
        txid1 = self.nodes[0].sendfrom("foo", node1_address, 4000, 0)
        txid2 = self.nodes[0].sendfrom("bar", node1_address, 2000, 0)

        # Have node0 mine a block:
        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 50RVN for another
        # matured block, minus 40, minus 20, and minus transaction fees:
        expected = starting_balance + fund_foo_tx["fee"] + fund_bar_tx["fee"]
        if self.options.mine_block: expected += 5000
        expected += tx1["amount"] + tx1["fee"]
        expected += tx2["amount"] + tx2["fee"]
        assert_equal(self.nodes[0].getbalance(), expected)

        # foo and bar accounts should be debited:
        assert_equal(self.nodes[0].getbalance("foo", 0),
                     121900 + tx1["amount"] + tx1["fee"])
        assert_equal(self.nodes[0].getbalance("bar", 0),
                     2900 + tx2["amount"] + tx2["fee"])

        if self.options.mine_block:
            assert_equal(tx1["confirmations"], 1)
            assert_equal(tx2["confirmations"], 1)
            # Node1's "from0" balance should be both transaction amounts:
            assert_equal(self.nodes[1].getbalance("from0"),
                         -(tx1["amount"] + tx2["amount"]))
        else:
            assert_equal(tx1["confirmations"], 0)
            assert_equal(tx2["confirmations"], 0)

        # Now give doublespend and its parents to miner:
        self.nodes[2].sendrawtransaction(fund_foo_tx["hex"])
        self.nodes[2].sendrawtransaction(fund_bar_tx["hex"])
        doublespend_txid = self.nodes[2].sendrawtransaction(doublespend["hex"])
        # ... mine a block...
        self.nodes[2].generate(1)

        # Reconnect the split network, and sync chain:
        connect_nodes(self.nodes[1], 2)
        self.nodes[2].generate(1)  # Mine another block to make sure we sync
        sync_blocks(self.nodes)
        assert_equal(
            self.nodes[0].gettransaction(doublespend_txid)["confirmations"], 2)

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

        # Both transactions should be conflicted
        assert_equal(tx1["confirmations"], -2)
        assert_equal(tx2["confirmations"], -2)

        # Node0's total balance should be starting balance, plus 100RVN for
        # two more matured blocks, minus 1240 for the double-spend, plus fees (which are
        # negative):
        expected = starting_balance + 10000 - 124000 + fund_foo_tx[
            "fee"] + fund_bar_tx["fee"] + doublespend_fee
        assert_equal(self.nodes[0].getbalance(), expected)
        assert_equal(self.nodes[0].getbalance("*"), expected)

        # Final "" balance is starting_balance - amount moved to accounts - doublespend + subsidies +
        # fees (which are negative)
        assert_equal(self.nodes[0].getbalance("foo"), 121900)
        assert_equal(self.nodes[0].getbalance("bar"), 2900)
        assert_equal(
            self.nodes[0].getbalance(""),
            starting_balance - 121900 - 2900 - 124000 + 10000 +
            fund_foo_tx["fee"] + fund_bar_tx["fee"] + doublespend_fee)

        # Node1's "from0" account balance should be just the doublespend:
        assert_equal(self.nodes[1].getbalance("from0"), 124000)
Beispiel #14
0
    def run_test(self):
        print("Mining blocks...")

        min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']
        # This test is not meant to test fee estimation and we'd like
        # to be sure all txs are sent at a consistent desired feerate
        for node in self.nodes:
            node.settxfee(min_relay_tx_fee)

        # if the fee's positive delta is higher than this value tests will fail,
        # neg. delta always fail the tests.
        # The size of the signature of every input may be at most 2 bytes larger
        # than a minimum sized signature.

        #            = 2 bytes * minRelayTxFeePerByte
        feeTolerance = 2 * min_relay_tx_fee / 1000

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

        watchonly_address = self.nodes[0].getnewaddress()
        watchonly_pubkey = self.nodes[0].validateaddress(
            watchonly_address)["pubkey"]
        watchonly_amount = Decimal(200)
        self.nodes[3].importpubkey(watchonly_pubkey, "", True)
        watchonly_txid = self.nodes[0].sendtoaddress(watchonly_address,
                                                     watchonly_amount)
        self.nodes[0].sendtoaddress(self.nodes[3].getnewaddress(),
                                    watchonly_amount / 10)

        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.nodes[0].generate(1)
        self.sync_all()

        ###############
        # simple test #
        ###############
        inputs = []
        outputs = {self.nodes[0].getnewaddress(): 1.0}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        assert (len(dec_tx['vin']) > 0)  #test if we have enought inputs

        ##############################
        # simple test with two coins #
        ##############################
        inputs = []
        outputs = {self.nodes[0].getnewaddress(): 2.2}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        assert (len(dec_tx['vin']) > 0)  #test if we have enough inputs

        ##############################
        # simple test with two coins #
        ##############################
        inputs = []
        outputs = {self.nodes[0].getnewaddress(): 2.6}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        assert (len(dec_tx['vin']) > 0)
        assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')

        ################################
        # simple test with two outputs #
        ################################
        inputs = []
        outputs = {
            self.nodes[0].getnewaddress(): 2.6,
            self.nodes[1].getnewaddress(): 2.5
        }
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        for out in dec_tx['vout']:
            totalOut += out['value']

        assert (len(dec_tx['vin']) > 0)
        assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')

        #########################################################################
        # test a fundrawtransaction with a VIN greater than the required amount #
        #########################################################################
        utx = get_unspent(self.nodes[2].listunspent(), 5)

        inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        outputs = {self.nodes[0].getnewaddress(): 1.0}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        for out in dec_tx['vout']:
            totalOut += out['value']

        assert_equal(fee + totalOut,
                     utx['amount'])  #compare vin total and totalout+fee

        #####################################################################
        # test a fundrawtransaction with which will not get a change output #
        #####################################################################
        utx = get_unspent(self.nodes[2].listunspent(), 5)

        inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        outputs = {
            self.nodes[0].getnewaddress(): Decimal(5.0) - fee - feeTolerance
        }
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        for out in dec_tx['vout']:
            totalOut += out['value']

        assert_equal(rawtxfund['changepos'], -1)
        assert_equal(fee + totalOut,
                     utx['amount'])  #compare vin total and totalout+fee

        ####################################################
        # test a fundrawtransaction with an invalid option #
        ####################################################
        utx = get_unspent(self.nodes[2].listunspent(), 5)

        inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        outputs = {self.nodes[0].getnewaddress(): Decimal(4.0)}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        try:
            self.nodes[2].fundrawtransaction(rawtx, {'foo': 'bar'})
            raise AssertionError("Accepted invalid option foo")
        except JSONRPCException as e:
            assert ("Unexpected key foo" in e.error['message'])

        ############################################################
        # test a fundrawtransaction with an invalid change address #
        ############################################################
        utx = get_unspent(self.nodes[2].listunspent(), 5)

        inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        outputs = {self.nodes[0].getnewaddress(): Decimal(4.0)}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        try:
            self.nodes[2].fundrawtransaction(rawtx,
                                             {'changeAddress': 'foobar'})
            raise AssertionError("Accepted invalid pivxl address")
        except JSONRPCException as e:
            assert ("changeAddress must be a valid pivxl address"
                    in e.error['message'])

        ############################################################
        # test a fundrawtransaction with a provided change address #
        ############################################################
        utx = get_unspent(self.nodes[2].listunspent(), 5)

        inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        outputs = {self.nodes[0].getnewaddress(): Decimal(4.0)}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        change = self.nodes[2].getnewaddress()
        try:
            rawtxfund = self.nodes[2].fundrawtransaction(
                rawtx, {
                    'changeAddress': change,
                    'changePosition': 2
                })
        except JSONRPCException as e:
            assert ('changePosition out of bounds' == e.error['message'])
        else:
            assert (False)
        rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {
            'changeAddress': change,
            'changePosition': 0
        })
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        out = dec_tx['vout'][0]
        assert_equal(change, out['scriptPubKey']['addresses'][0])

        #########################################################################
        # test a fundrawtransaction with a VIN smaller than the required amount #
        #########################################################################
        utx = get_unspent(self.nodes[2].listunspent(), 1)

        inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        outputs = {self.nodes[0].getnewaddress(): 1.0}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)

        # 4-byte version + 1-byte vin count + 36-byte prevout then script_len
        rawtx = rawtx[:82] + "0100" + rawtx[84:]

        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
        assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        matchingOuts = 0
        for i, out in enumerate(dec_tx['vout']):
            totalOut += out['value']
            if out['scriptPubKey']['addresses'][0] in outputs:
                matchingOuts += 1
            else:
                assert_equal(i, rawtxfund['changepos'])

        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
        assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])

        assert_equal(matchingOuts, 1)
        assert_equal(len(dec_tx['vout']), 2)

        ###########################################
        # test a fundrawtransaction with two VINs #
        ###########################################
        utx = get_unspent(self.nodes[2].listunspent(), 1)
        utx2 = get_unspent(self.nodes[2].listunspent(), 5)

        inputs = [{
            'txid': utx['txid'],
            'vout': utx['vout']
        }, {
            'txid': utx2['txid'],
            'vout': utx2['vout']
        }]
        outputs = {self.nodes[0].getnewaddress(): 6.0}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        matchingOuts = 0
        for out in dec_tx['vout']:
            totalOut += out['value']
            if out['scriptPubKey']['addresses'][0] in outputs:
                matchingOuts += 1

        assert_equal(matchingOuts, 1)
        assert_equal(len(dec_tx['vout']), 2)

        matchingIns = 0
        for vinOut in dec_tx['vin']:
            for vinIn in inputs:
                if vinIn['txid'] == vinOut['txid']:
                    matchingIns += 1

        assert_equal(
            matchingIns,
            2)  #we now must see two vins identical to vins given as params

        #########################################################
        # test a fundrawtransaction with two VINs and two vOUTs #
        #########################################################
        utx = get_unspent(self.nodes[2].listunspent(), 1)
        utx2 = get_unspent(self.nodes[2].listunspent(), 5)

        inputs = [{
            'txid': utx['txid'],
            'vout': utx['vout']
        }, {
            'txid': utx2['txid'],
            'vout': utx2['vout']
        }]
        outputs = {
            self.nodes[0].getnewaddress(): 6.0,
            self.nodes[0].getnewaddress(): 1.0
        }
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        matchingOuts = 0
        for out in dec_tx['vout']:
            totalOut += out['value']
            if out['scriptPubKey']['addresses'][0] in outputs:
                matchingOuts += 1

        assert_equal(matchingOuts, 2)
        assert_equal(len(dec_tx['vout']), 3)

        ##############################################
        # test a fundrawtransaction with invalid vin #
        ##############################################
        listunspent = self.nodes[2].listunspent()
        inputs = [{
            'txid':
            "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1",
            'vout': 0
        }]  #invalid vin!
        outputs = {self.nodes[0].getnewaddress(): 1.0}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)

        try:
            rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
            raise AssertionError("Spent more than available")
        except JSONRPCException as e:
            assert ("Insufficient" in e.error['message'])

        ############################################################
        #compare fee of a standard pubkeyhash transaction
        inputs = []
        outputs = {self.nodes[1].getnewaddress(): 1.1}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1)
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert (feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################

        ############################################################
        #compare fee of a standard pubkeyhash transaction with multiple outputs
        inputs = []
        outputs = {
            self.nodes[1].getnewaddress(): 1.1,
            self.nodes[1].getnewaddress(): 1.2,
            self.nodes[1].getnewaddress(): 0.1,
            self.nodes[1].getnewaddress(): 1.3,
            self.nodes[1].getnewaddress(): 0.2,
            self.nodes[1].getnewaddress(): 0.3
        }
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)
        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendmany("", outputs)
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert (feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################

        ############################################################
        #compare fee of a 2of2 multisig p2sh transaction

        # create 2of2 addr
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[1].getnewaddress()

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

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

        inputs = []
        outputs = {mSigObj: 1.1}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert (feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################

        ############################################################
        #compare fee of a standard pubkeyhash transaction

        # create 4of5 addr
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[1].getnewaddress()
        addr3 = self.nodes[1].getnewaddress()
        addr4 = self.nodes[1].getnewaddress()
        addr5 = self.nodes[1].getnewaddress()

        addr1Obj = self.nodes[1].validateaddress(addr1)
        addr2Obj = self.nodes[1].validateaddress(addr2)
        addr3Obj = self.nodes[1].validateaddress(addr3)
        addr4Obj = self.nodes[1].validateaddress(addr4)
        addr5Obj = self.nodes[1].validateaddress(addr5)

        mSigObj = self.nodes[1].addmultisigaddress(4, [
            addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey'],
            addr4Obj['pubkey'], addr5Obj['pubkey']
        ])

        inputs = []
        outputs = {mSigObj: 1.1}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert (feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################

        ############################################################
        # spend a 2of2 multisig transaction over fundraw

        # create 2of2 addr
        addr1 = self.nodes[2].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

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

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

        # send 1.2 BTC to msig addr
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        oldBalance = self.nodes[1].getbalance()
        inputs = []
        outputs = {self.nodes[1].getnewaddress(): 1.1}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[2].fundrawtransaction(rawTx)

        signedTx = self.nodes[2].signrawtransaction(fundedTx['hex'])
        txId = self.nodes[2].sendrawtransaction(signedTx['hex'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # make sure funds are received at node1
        assert_equal(oldBalance + Decimal('1.10000000'),
                     self.nodes[1].getbalance())

        ############################################################
        # locked wallet test
        self.nodes[1].encryptwallet("test")
        self.nodes.pop(1)
        self.stop_nodes()

        self.nodes = self.start_nodes()
        # This test is not meant to test fee estimation and we'd like
        # to be sure all txs are sent at a consistent desired feerate
        for node in self.nodes:
            node.settxfee(min_relay_tx_fee)

        connect_nodes(self.nodes[0], 1)
        connect_nodes(self.nodes[1], 2)
        connect_nodes(self.nodes[0], 2)
        connect_nodes(self.nodes[0], 3)
        self.is_network_split = False
        self.sync_all()

        # drain the keypool
        self.nodes[1].getnewaddress()
        inputs = []
        outputs = {self.nodes[0].getnewaddress(): 1.1}
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
        # fund a transaction that requires a new key for the change output
        # creating the key must be impossible because the wallet is locked
        try:
            fundedTx = self.nodes[1].fundrawtransaction(rawTx)
            raise AssertionError("Wallet unlocked without passphrase")
        except JSONRPCException as e:
            assert ('Keypool ran out' in e.error['message'])

        #refill the keypool
        self.nodes[1].walletpassphrase("test", 100)
        self.nodes[1].walletlock()

        try:
            self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2)
            raise AssertionError("Wallet unlocked without passphrase")
        except JSONRPCException as e:
            assert ('walletpassphrase' in e.error['message'])

        oldBalance = self.nodes[0].getbalance()

        inputs = []
        outputs = {self.nodes[0].getnewaddress(): 1.1}
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[1].fundrawtransaction(rawTx)

        #now we need to unlock
        self.nodes[1].walletpassphrase("test", 100)
        signedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])
        txId = self.nodes[1].sendrawtransaction(signedTx['hex'])
        self.nodes[1].generate(1)
        self.sync_all()

        # make sure funds are received at node1
        assert_equal(oldBalance + Decimal('51.10000000'),
                     self.nodes[0].getbalance())

        ###############################################
        # multiple (~19) inputs tx test | Compare fee #
        ###############################################

        #empty node1, send some small coins from node0 to node1
        self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(),
                                    self.nodes[1].getbalance(), "", "", True)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        for i in range(0, 20):
            self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01)
        self.nodes[0].generate(1)
        self.sync_all()

        #fund a tx with ~20 small inputs
        inputs = []
        outputs = {
            self.nodes[0].getnewaddress(): 0.15,
            self.nodes[0].getnewaddress(): 0.04
        }
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[1].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[1].sendmany("", outputs)
        signedFee = self.nodes[1].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert (feeDelta >= 0 and feeDelta <= feeTolerance * 19)  #~19 inputs

        #############################################
        # multiple (~19) inputs tx test | sign/send #
        #############################################

        #again, empty node1, send some small coins from node0 to node1
        self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(),
                                    self.nodes[1].getbalance(), "", "", True)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        for i in range(0, 20):
            self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01)
        self.nodes[0].generate(1)
        self.sync_all()

        #fund a tx with ~20 small inputs
        oldBalance = self.nodes[0].getbalance()

        inputs = []
        outputs = {
            self.nodes[0].getnewaddress(): 0.15,
            self.nodes[0].getnewaddress(): 0.04
        }
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[1].fundrawtransaction(rawTx)
        fundedAndSignedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])
        txId = self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(oldBalance + Decimal('50.19000000'),
                     self.nodes[0].getbalance())  #0.19+block reward

        #####################################################
        # test fundrawtransaction with OP_RETURN and no vin #
        #####################################################

        rawtx = "0100000000010000000000000000066a047465737400000000"
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)

        assert_equal(len(dec_tx['vin']), 0)
        assert_equal(len(dec_tx['vout']), 1)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])

        assert_greater_than(len(dec_tx['vin']), 0)  # at least one vin
        assert_equal(len(dec_tx['vout']), 2)  # one change output added

        ##################################################
        # test a fundrawtransaction using only watchonly #
        ##################################################

        inputs = []
        outputs = {self.nodes[2].getnewaddress(): watchonly_amount / 2}
        rawtx = self.nodes[3].createrawtransaction(inputs, outputs)

        result = self.nodes[3].fundrawtransaction(rawtx,
                                                  {'includeWatching': True})
        res_dec = self.nodes[0].decoderawtransaction(result["hex"])
        assert_equal(len(res_dec["vin"]), 1)
        assert_equal(res_dec["vin"][0]["txid"], watchonly_txid)

        assert ("fee" in result.keys())
        assert_greater_than(result["changepos"], -1)

        ###############################################################
        # test fundrawtransaction using the entirety of watched funds #
        ###############################################################

        inputs = []
        outputs = {self.nodes[2].getnewaddress(): watchonly_amount}
        rawtx = self.nodes[3].createrawtransaction(inputs, outputs)

        # Backward compatibility test (2nd param is includeWatching)
        result = self.nodes[3].fundrawtransaction(rawtx, True)
        res_dec = self.nodes[0].decoderawtransaction(result["hex"])
        assert_equal(len(res_dec["vin"]), 2)
        assert (res_dec["vin"][0]["txid"] == watchonly_txid
                or res_dec["vin"][1]["txid"] == watchonly_txid)

        assert_greater_than(result["fee"], 0)
        assert_greater_than(result["changepos"], -1)
        assert_equal(
            result["fee"] + res_dec["vout"][result["changepos"]]["value"],
            watchonly_amount / 10)

        signedtx = self.nodes[3].signrawtransaction(result["hex"])
        assert (not signedtx["complete"])
        signedtx = self.nodes[0].signrawtransaction(signedtx["hex"])
        assert (signedtx["complete"])
        self.nodes[0].sendrawtransaction(signedtx["hex"])
        self.nodes[0].generate(1)
        self.sync_all()

        #######################
        # Test feeRate option #
        #######################

        # Make sure there is exactly one input so coin selection can't skew the result
        assert_equal(len(self.nodes[3].listunspent(1)), 1)

        inputs = []
        outputs = {self.nodes[2].getnewaddress(): 1}
        rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
        result = self.nodes[3].fundrawtransaction(
            rawtx)  # uses min_relay_tx_fee (set by settxfee)
        result2 = self.nodes[3].fundrawtransaction(
            rawtx, {"feeRate": 2 * min_relay_tx_fee})
        result3 = self.nodes[3].fundrawtransaction(
            rawtx, {"feeRate": 10 * min_relay_tx_fee})
        result_fee_rate = result['fee'] * 1000 / count_bytes(result['hex'])
        assert_fee_amount(result2['fee'], count_bytes(result2['hex']),
                          2 * result_fee_rate)
        assert_fee_amount(result3['fee'], count_bytes(result3['hex']),
                          10 * result_fee_rate)
Beispiel #15
0
    def run_test(self):
        # Check that there's no UTXO on none of the nodes
        assert_equal(len(self.nodes[0].listunspent()), 0)
        assert_equal(len(self.nodes[1].listunspent()), 0)
        assert_equal(len(self.nodes[2].listunspent()), 0)

        self.log.info("Mining blocks...")

        self.nodes[0].generate(1)

        walletinfo = self.nodes[0].getwalletinfo()
        self.check_wallet_processed_blocks(0, walletinfo)
        assert_equal(walletinfo['immature_balance'], 250)
        assert_equal(walletinfo['balance'], 0)

        self.sync_all(self.nodes[0:3])
        self.nodes[1].generate(101)
        self.sync_all(self.nodes[0:3])

        assert_equal(self.nodes[0].getbalance(), 250)
        assert_equal(self.nodes[1].getbalance(), 250)
        assert_equal(self.nodes[2].getbalance(), 0)

        walletinfo = self.nodes[0].getwalletinfo()
        self.check_wallet_processed_blocks(0, walletinfo)
        self.check_wallet_processed_blocks(1, self.nodes[1].getwalletinfo())
        self.check_wallet_processed_blocks(2, self.nodes[2].getwalletinfo())

        # Check that only first and second nodes have UTXOs
        utxos = self.nodes[0].listunspent()
        assert_equal(len(utxos), 1)
        assert_equal(len(self.nodes[1].listunspent()), 1)
        assert_equal(len(self.nodes[2].listunspent()), 0)

        assert_equal(walletinfo['immature_balance'], 0)

        # Exercise locking of unspent outputs
        unspent_0 = self.nodes[1].listunspent()[0]
        assert unspent_0["solvable"]
        assert unspent_0["spendable"]
        assert unspent_0["safe"]
        unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]}
        self.nodes[1].lockunspent(False, [unspent_0])
        assert_raises_rpc_error(-4, "Insufficient funds",
                                self.nodes[1].sendtoaddress,
                                self.nodes[1].getnewaddress(), 20)
        assert_equal([unspent_0], self.nodes[1].listlockunspent())
        self.nodes[1].lockunspent(True, [unspent_0])
        assert_equal(len(self.nodes[1].listlockunspent()), 0)

        # Send 21 PIV from 1 to 0 using sendtoaddress call.
        # Locked memory should use at least 32 bytes to sign the transaction
        self.log.info("test getmemoryinfo")
        memory_before = self.nodes[0].getmemoryinfo()
        self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 21)
        memory_after = self.nodes[0].getmemoryinfo()
        assert (memory_before['locked']['used'] + 32 <=
                memory_after['locked']['used'])
        self.sync_mempools(self.nodes[0:3])

        # Node0 should have two unspent outputs.
        # One safe, the other one not yet
        node0utxos = self.nodes[0].listunspent(0)
        assert_equal(len(node0utxos), 2)
        newutxos = [x for x in node0utxos if x["txid"] != utxos[0]["txid"]]
        assert_equal(len(newutxos), 1)
        assert not newutxos[0]["safe"]

        # Mine the other tx
        self.nodes[1].generate(1)
        self.sync_all(self.nodes[0:3])
        node0utxos = self.nodes[0].listunspent()
        assert_equal(len(node0utxos), 2)
        for u in node0utxos:
            assert u["safe"]

        # Create a couple of transactions to send them to node2, submit them through
        # node1, and make sure both node0 and node2 pick them up properly:
        # create both transactions
        fee_per_kbyte = Decimal('0.001')
        txns_to_send = []
        for utxo in node0utxos:
            inputs = []
            outputs = {}
            inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]})
            outputs[self.nodes[2].getnewaddress()] = float(
                utxo["amount"]) - float(fee_per_kbyte)
            raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
            txns_to_send.append(self.nodes[0].signrawtransaction(raw_tx))

        # Have node 1 (miner) send the transactions
        self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], True)
        self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], True)

        # Have node1 mine a block to confirm transactions:
        self.nodes[1].generate(1)
        self.sync_all(self.nodes[0:3])

        assert_equal(self.nodes[0].getbalance(), 0)
        node_2_expected_bal = Decimal('250') + Decimal(
            '21') - 2 * fee_per_kbyte
        node_2_bal = self.nodes[2].getbalance()
        assert_equal(node_2_bal, node_2_expected_bal)

        # Send 10 PIV normal
        self.log.info("test sendtoaddress")
        address = self.nodes[0].getnewaddress("test")
        self.nodes[2].settxfee(float(fee_per_kbyte))
        txid = self.nodes[2].sendtoaddress(address, 10, "", "")
        fee = self.nodes[2].gettransaction(txid)["fee"]  # fee < 0
        node_2_bal -= (Decimal('10') - fee)
        assert_equal(self.nodes[2].getbalance(), node_2_bal)
        self.nodes[2].generate(1)
        self.sync_all(self.nodes[0:3])
        node_0_bal = self.nodes[0].getbalance()
        assert_equal(node_0_bal, Decimal('10'))

        # Sendmany 10 PIV
        self.log.info("test sendmany")
        txid = self.nodes[2].sendmany('', {address: 10}, 0, "")
        fee = self.nodes[2].gettransaction(txid)["fee"]
        self.nodes[2].generate(1)
        self.sync_all(self.nodes[0:3])
        node_0_bal += Decimal('10')
        node_2_bal -= (Decimal('10') - fee)
        assert_equal(self.nodes[2].getbalance(), node_2_bal)
        assert_equal(self.nodes[0].getbalance(), node_0_bal)
        assert_fee_amount(
            -fee, self.get_vsize(self.nodes[2].getrawtransaction(txid)),
            fee_per_kbyte)

        # Import address and private key to check correct behavior of spendable unspents
        # 1. Send some coins to generate new UTXO
        address_to_import = self.nodes[2].getnewaddress()
        self.nodes[0].sendtoaddress(address_to_import, 1)
        self.nodes[0].generate(1)
        self.sync_all(self.nodes[0:3])

        # 2. Import address from node2 to node1
        self.log.info("test importaddress")
        self.nodes[1].importaddress(address_to_import)

        # 3. Validate that the imported address is watch-only on node1
        assert (
            self.nodes[1].validateaddress(address_to_import)["iswatchonly"])

        # 4. Check that the unspents after import are not spendable
        listunspent = self.nodes[1].listunspent(1, 9999999, [], 2)
        assert_array_result(listunspent, {"address": address_to_import},
                            {"spendable": False})

        # 5. Import private key of the previously imported address on node1
        priv_key = self.nodes[2].dumpprivkey(address_to_import)
        self.log.info("test importprivkey")
        self.nodes[1].importprivkey(priv_key)

        # 6. Check that the unspents are now spendable on node1
        assert_array_result(self.nodes[1].listunspent(),
                            {"address": address_to_import},
                            {"spendable": True})

        # check if wallet or blochchain maintenance changes the balance
        self.sync_all(self.nodes[0:3])
        blocks = self.nodes[0].generate(2)
        self.sync_all(self.nodes[0:3])
        balance_nodes = [self.nodes[i].getbalance() for i in range(3)]
        block_count = self.nodes[0].getblockcount()

        maintenance = [
            '-rescan',
            '-reindex',
        ]
        for m in maintenance:
            self.log.info("check " + m)
            self.stop_nodes()
            # set lower ancestor limit for later
            self.start_node(0, [m])
            self.start_node(1, [m])
            self.start_node(2, [m])
            if m == '-reindex':
                # reindex will leave rpc warm up "early"; Wait for it to finish
                wait_until(lambda: [block_count] * 3 ==
                           [self.nodes[i].getblockcount() for i in range(3)])
            assert_equal(balance_nodes,
                         [self.nodes[i].getbalance() for i in range(3)])

        # Exercise listsinceblock with the last two blocks
        self.check_wallet_processed_blocks(0, self.nodes[0].getwalletinfo())
        coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0])
        assert_equal(coinbase_tx_1["lastblock"], blocks[1])
        assert_equal(len(coinbase_tx_1["transactions"]), 1)
        assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1])
        assert_equal(
            len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0)

        # Excercise query_options parameter in listunspent
        # Node 1 has:
        # - 1 coin of 1.00 PIV
        # - 7 coins of 250.00 PIV
        # - 1 coin of 228.9999xxxx PIV
        assert_equal(9, self.len_listunspent({}))
        assert_equal(9, self.len_listunspent({"maximumCount": 10}))
        assert_equal(2, self.len_listunspent({"maximumCount": 2}))
        assert_equal(1, self.len_listunspent({"maximumCount": 1}))
        assert_equal(9, self.len_listunspent({"maximumCount": 0}))
        assert_equal(9, self.len_listunspent({"minimumAmount": 0.99999999}))
        assert_equal(9, self.len_listunspent({"minimumAmount": 1.00}))
        assert_equal(8, self.len_listunspent({"minimumAmount": 1.00000001}))
        assert_equal(8, self.len_listunspent({"minimumAmount": 228.9999}))
        assert_equal(7, self.len_listunspent({"minimumAmount": 229.00}))
        assert_equal(7, self.len_listunspent({"minimumAmount": 250.00}))
        assert_equal(0, self.len_listunspent({"minimumAmount": 250.00000001}))
        assert_equal(0, self.len_listunspent({"maximumAmount": 0.99999999}))
        assert_equal(1, self.len_listunspent({"maximumAmount": 1.00}))
        assert_equal(1, self.len_listunspent({"maximumAmount": 228.9999}))
        assert_equal(2, self.len_listunspent({"maximumAmount": 229.00}))
        assert_equal(2, self.len_listunspent({"maximumAmount": 249.99999999}))
        assert_equal(9, self.len_listunspent({"maximumAmount": 250.00}))
        assert_equal(
            9,
            self.len_listunspent({
                "minimumAmount": 1.00000000,
                "maximumAmount": 250.00
            }))
        assert_equal(
            2,
            self.len_listunspent({
                "minimumAmount": 1.00000000,
                "maximumAmount": 249.99999999
            }))
        assert_equal(
            8,
            self.len_listunspent({
                "minimumAmount": 1.00000001,
                "maximumAmount": 250.00
            }))
        assert_equal(
            7,
            self.len_listunspent({
                "minimumAmount": 229.000000,
                "maximumAmount": 250.00
            }))
        assert_equal(
            7,
            self.len_listunspent({
                "minimumAmount": 250.000000,
                "maximumAmount": 250.00
            }))
        assert_equal(
            8,
            self.len_listunspent({
                "minimumAmount": 228.999900,
                "maximumAmount": 250.00
            }))
        assert_equal(
            0,
            self.len_listunspent({
                "minimumAmount": 228.999900,
                "maximumAmount": 228.00
            }))
        assert_equal(
            1,
            self.len_listunspent({
                "minimumAmount": 250.00,
                "minimumSumAmount": 249.99999999
            }))
        assert_equal(
            2,
            self.len_listunspent({
                "minimumAmount": 250.00,
                "minimumSumAmount": 250.00000001
            }))
        assert_equal(
            5,
            self.len_listunspent({
                "minimumAmount": 250.00,
                "minimumSumAmount": 1250.0000000
            }))
        assert_equal(9, self.len_listunspent({"minimumSumAmount": 2500.00}))
Beispiel #16
0
    def run_test(self):
        """
        listreceivedbyaddress Test
        """
        # Send from node 0 to 1
        addr = self.nodes[1].getnewaddress()
        txid = self.nodes[0].sendtoaddress(addr, 0.1)
        self.sync_all()

        #Check not listed in listreceivedbyaddress because has 0 confirmations
        assert_array_result(self.nodes[1].listreceivedbyaddress(),
                            {"address": addr}, {}, True)
        #Bury Tx under 10 block so it will be returned by listreceivedbyaddress
        self.nodes[1].generate(10)
        self.sync_all()
        assert_array_result(self.nodes[1].listreceivedbyaddress(),
                            {"address": addr}, {
                                "address": addr,
                                "account": "",
                                "amount": Decimal("0.1"),
                                "confirmations": 10,
                                "txids": [
                                    txid,
                                ]
                            })
        #With min confidence < 10
        assert_array_result(self.nodes[1].listreceivedbyaddress(5),
                            {"address": addr}, {
                                "address": addr,
                                "account": "",
                                "amount": Decimal("0.1"),
                                "confirmations": 10,
                                "txids": [
                                    txid,
                                ]
                            })
        #With min confidence > 10, should not find Tx
        assert_array_result(self.nodes[1].listreceivedbyaddress(11),
                            {"address": addr}, {}, True)

        #Empty Tx
        addr = self.nodes[1].getnewaddress()
        assert_array_result(self.nodes[1].listreceivedbyaddress(0, True),
                            {"address": addr}, {
                                "address": addr,
                                "account": "",
                                "amount": 0,
                                "confirmations": 0,
                                "txids": []
                            })
        '''
            getreceivedbyaddress Test
        '''
        # Send from node 0 to 1
        addr = self.nodes[1].getnewaddress()
        self.nodes[0].sendtoaddress(addr, 0.1)
        self.sync_all()

        # Check balance is 0 because of 0 confirmations
        balance = self.nodes[1].getreceivedbyaddress(addr)
        if balance != Decimal("0.0"):
            raise AssertionError(
                "Wrong balance returned by getreceivedbyaddress, %0.2f" %
                balance)

        # Check balance is 0.1
        balance = self.nodes[1].getreceivedbyaddress(addr, 0)
        if balance != Decimal("0.1"):
            raise AssertionError(
                "Wrong balance returned by getreceivedbyaddress, %0.2f" %
                balance)

        # Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress
        self.nodes[1].generate(10)
        self.sync_all()
        balance = self.nodes[1].getreceivedbyaddress(addr)
        if balance != Decimal("0.1"):
            raise AssertionError(
                "Wrong balance returned by getreceivedbyaddress, %0.2f" %
                balance)
        '''
            listreceivedbyaccount + getreceivedbyaccount Test
        '''
        # set pre-state
        addrArr = self.nodes[1].getnewaddress()
        account = self.nodes[1].getaccount(addrArr)
        received_by_account_json = get_sub_array_from_array(
            self.nodes[1].listreceivedbyaccount(), {"account": account})
        if len(received_by_account_json) == 0:
            raise AssertionError("No accounts found in node")
        balance_by_account = self.nodes[1].getreceivedbyaccount(account)

        self.nodes[0].sendtoaddress(addr, 0.1)
        self.sync_all()

        # listreceivedbyaccount should return received_by_account_json because of 0 confirmations
        assert_array_result(self.nodes[1].listreceivedbyaccount(),
                            {"account": account}, received_by_account_json)

        # getreceivedbyaddress should return same balance because of 0 confirmations
        balance = self.nodes[1].getreceivedbyaccount(account)
        if balance != balance_by_account:
            raise AssertionError(
                "Wrong balance returned by getreceivedbyaccount, %0.2f" %
                balance)

        self.nodes[1].generate(10)
        self.sync_all()
        # listreceivedbyaccount should return updated account balance
        assert_array_result(
            self.nodes[1].listreceivedbyaccount(), {"account": account}, {
                "account": received_by_account_json["account"],
                "amount": (received_by_account_json["amount"] + Decimal("0.1"))
            })

        # getreceivedbyaddress should return updates balance
        balance = self.nodes[1].getreceivedbyaccount(account)
        if balance != balance_by_account + Decimal("0.1"):
            raise AssertionError(
                "Wrong balance returned by getreceivedbyaccount, %0.2f" %
                balance)

        # Create a new account named "mynewaccount" that has a 0 balance
        self.nodes[1].getaccountaddress("mynewaccount")
        received_by_account_json = get_sub_array_from_array(
            self.nodes[1].listreceivedbyaccount(0, True),
            {"account": "mynewaccount"})
        if len(received_by_account_json) == 0:
            raise AssertionError("No accounts found in node")

        # Test include empty of listreceivedbyaccount
        if received_by_account_json["amount"] != Decimal("0.0"):
            raise AssertionError(
                "Wrong balance returned by listreceivedbyaccount, %0.2f" %
                (received_by_account_json["amount"]))

        # Test getreceivedbyaccount for 0 amount accounts
        balance = self.nodes[1].getreceivedbyaccount("mynewaccount")
        if balance != Decimal("0.0"):
            raise AssertionError(
                "Wrong balance returned by getreceivedbyaccount, %0.2f" %
                balance)
Beispiel #17
0
    def run_test(self):
        miner = self.nodes[0]
        owner = self.nodes[1]
        remote = self.nodes[2]
        mnPrivkey = "9247iC59poZmqBYt9iDh9wDam6v9S1rW5XekjLGyPnDhrDkP4AK"

        self.log.info("generating 141 blocks...")
        miner.generate(141)
        self.sync_blocks()

        # Create collateral
        self.log.info("funding masternode controller...")
        masternodeAlias = "mnode"
        mnAddress = owner.getnewaddress(masternodeAlias)
        collateralTxId = miner.sendtoaddress(mnAddress, Decimal('100'))
        miner.generate(2)
        self.sync_blocks()
        time.sleep(1)
        collateral_rawTx = owner.getrawtransaction(collateralTxId, 1)
        assert_equal(owner.getbalance(), Decimal('100'))
        assert_greater_than(collateral_rawTx["confirmations"], 0)

        # Block time can be up to median time past +1. We might need to wait...
        wait_time = collateral_rawTx["time"] - int(time.time())
        if wait_time > 0:
            self.log.info("Sleep %d seconds to catch up with the chain..." %
                          wait_time)
            time.sleep(wait_time)

        # Setup controller
        self.log.info("controller setup...")
        o = owner.getmasternodeoutputs()
        assert_equal(len(o), 1)
        assert_equal(o[0]["txhash"], collateralTxId)
        vout = o[0]["outputidx"]
        self.log.info("collateral accepted for " + masternodeAlias +
                      ". Updating masternode.conf...")
        confData = masternodeAlias + " 127.0.0.1:" + str(p2p_port(2)) + " " + \
                   str(mnPrivkey) +  " " + str(collateralTxId) + " " + str(vout)
        destPath = os.path.join(self.options.tmpdir, "node1", "regtest",
                                "masternode.conf")
        with open(destPath, "a+") as file_object:
            file_object.write("\n")
            file_object.write(confData)

        # Init remote
        self.log.info("initializing remote masternode...")
        remote.initmasternode(mnPrivkey, "127.0.0.1:" + str(p2p_port(2)))

        # sanity check, verify that we are not in IBD
        for i in range(0, len(self.nodes)):
            node = self.nodes[i]
            if (node.getblockchaininfo()['initial_block_downloading']):
                raise AssertionError("Error, node(%s) shouldn't be in IBD." %
                                     str(i))

        # Wait until mnsync is complete (max 120 seconds)
        self.log.info("waiting to complete mnsync...")
        start_time = time.time()
        self.wait_until_mnsync_finished()
        self.log.info("MnSync completed in %d seconds" %
                      (time.time() - start_time))
        miner.generate(1)
        self.sync_blocks()
        time.sleep(1)

        # Send Start message
        self.log.info("sending masternode broadcast...")
        self.controller_start_masternode(owner, masternodeAlias)
        miner.generate(1)
        self.sync_blocks()
        time.sleep(1)

        # Wait until masternode is enabled everywhere (max 180 secs)
        self.log.info("waiting till masternode gets enabled...")
        start_time = time.time()
        time.sleep(5)
        self.wait_until_mn_enabled(collateralTxId, 180)
        self.log.info("Masternode enabled in %d seconds" %
                      (time.time() - start_time))
        self.log.info("Good. Masternode enabled")
        miner.generate(1)
        self.sync_blocks()
        time.sleep(1)

        last_seen = [
            self.get_mn_lastseen(node, collateralTxId) for node in self.nodes
        ]
        self.log.info("Current lastseen: %s" % str(last_seen))
        self.log.info("Waiting 2 * 25 seconds and check new lastseen...")
        time.sleep(50)
        new_last_seen = [
            self.get_mn_lastseen(node, collateralTxId) for node in self.nodes
        ]
        self.log.info("New lastseen: %s" % str(new_last_seen))
        for i in range(self.num_nodes):
            assert_greater_than(new_last_seen[i], last_seen[i])
        self.log.info("All good.")
Beispiel #18
0
    def run_test(self):
        """ Mine some blocks and have them mature. """
        self.nodes[0].generate(101)
        utxo = self.nodes[0].listunspent(10)
        txid = utxo[0]['txid']
        vout = utxo[0]['vout']
        value = utxo[0]['amount']

        fee = Decimal("0.0001")
        # MAX_ANCESTORS transactions off a confirmed tx should be fine
        chain = []
        for i in range(MAX_ANCESTORS):
            (txid, sent_value) = self.chain_transaction(self.nodes[0], txid, 0, value, fee, 1)
            value = sent_value
            chain.append(txid)

        # Check mempool has MAX_ANCESTORS transactions in it, and descendant
        # count and fees should look correct
        mempool = self.nodes[0].getrawmempool(True)
        assert_equal(len(mempool), MAX_ANCESTORS)
        descendant_count = 1
        descendant_fees = 0
        descendant_size = 0

        descendants = []
        ancestors = list(chain)
        for x in reversed(chain):
            # Check that getmempoolentry is consistent with getrawmempool
            entry = self.nodes[0].getmempoolentry(x)
            assert_equal(entry, mempool[x])

            # Check that the descendant calculations are correct
            assert_equal(mempool[x]['descendantcount'], descendant_count)
            descendant_fees += mempool[x]['fee']
            assert_equal(mempool[x]['modifiedfee'], mempool[x]['fee'])
            assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN)
            descendant_size += mempool[x]['size']
            assert_equal(mempool[x]['descendantsize'], descendant_size)
            descendant_count += 1

            # Check that getmempooldescendants is correct
            assert_equal(sorted(descendants), sorted(self.nodes[0].getmempooldescendants(x)))
            descendants.append(x)

            # Check that getmempoolancestors is correct
            ancestors.remove(x)
            assert_equal(sorted(ancestors), sorted(self.nodes[0].getmempoolancestors(x)))

        # Check that getmempoolancestors/getmempooldescendants correctly handle verbose=true
        v_ancestors = self.nodes[0].getmempoolancestors(chain[-1], True)
        assert_equal(len(v_ancestors), len(chain)-1)
        for x in v_ancestors.keys():
            assert_equal(mempool[x], v_ancestors[x])
        assert(chain[-1] not in v_ancestors.keys())

        v_descendants = self.nodes[0].getmempooldescendants(chain[0], True)
        assert_equal(len(v_descendants), len(chain)-1)
        for x in v_descendants.keys():
            assert_equal(mempool[x], v_descendants[x])
        assert(chain[0] not in v_descendants.keys())

        # Check that ancestor modified fees includes fee deltas from
        # prioritisetransaction
        self.nodes[0].prioritisetransaction(txid=chain[0], fee_delta=1000)
        mempool = self.nodes[0].getrawmempool(True)
        ancestor_fees = 0
        for x in chain:
            ancestor_fees += mempool[x]['fee']
            assert_equal(mempool[x]['ancestorfees'], ancestor_fees * COIN + 1000)
        
        # Undo the prioritisetransaction for later tests
        self.nodes[0].prioritisetransaction(txid=chain[0], fee_delta=-1000)

        # Check that descendant modified fees includes fee deltas from
        # prioritisetransaction
        self.nodes[0].prioritisetransaction(txid=chain[-1], fee_delta=1000)
        mempool = self.nodes[0].getrawmempool(True)

        descendant_fees = 0
        for x in reversed(chain):
            descendant_fees += mempool[x]['fee']
            assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 1000)

        # Adding one more transaction on to the chain should fail.
        assert_raises_rpc_error(-26, "too-long-mempool-chain", self.chain_transaction, self.nodes[0], txid, vout, value, fee, 1)

        # Check that prioritising a tx before it's added to the mempool works
        # First clear the mempool by mining a block.
        self.nodes[0].generate(1)
        sync_blocks(self.nodes)
        assert_equal(len(self.nodes[0].getrawmempool()), 0)
        # Prioritise a transaction that has been mined, then add it back to the
        # mempool by using invalidateblock.
        self.nodes[0].prioritisetransaction(txid=chain[-1], fee_delta=2000)
        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
        # Keep node1's tip synced with node0
        self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())

        # Now check that the transaction is in the mempool, with the right modified fee
        mempool = self.nodes[0].getrawmempool(True)

        descendant_fees = 0
        for x in reversed(chain):
            descendant_fees += mempool[x]['fee']
            if x == chain[-1]:
                assert_equal(mempool[x]['modifiedfee'], mempool[x]['fee']+satoshi_round(0.00002))
            assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 2000)

        # TODO: check that node1's mempool is as expected

        # TODO: test ancestor size limits

        # Now test descendant chain limits
        txid = utxo[1]['txid']
        value = utxo[1]['amount']
        vout = utxo[1]['vout']

        transaction_package = []
        # First create one parent tx with 10 children
        (txid, sent_value) = self.chain_transaction(self.nodes[0], txid, vout, value, fee, 10)
        parent_transaction = txid
        for i in range(10):
            transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value})

        # Sign and send up to MAX_DESCENDANT transactions chained off the parent tx
        for i in range(MAX_DESCENDANTS - 1):
            utxo = transaction_package.pop(0)
            (txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)
            for j in range(10):
                transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value})

        mempool = self.nodes[0].getrawmempool(True)
        assert_equal(mempool[parent_transaction]['descendantcount'], MAX_DESCENDANTS)

        # Sending one more chained transaction will fail
        utxo = transaction_package.pop(0)
        assert_raises_rpc_error(-26, "too-long-mempool-chain", self.chain_transaction, self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)

        # TODO: check that node1's mempool is as expected

        # TODO: test descendant size limits

        # Test reorg handling
        # First, the basics:
        self.nodes[0].generate(1)
        sync_blocks(self.nodes)
        self.nodes[1].invalidateblock(self.nodes[0].getbestblockhash())
        self.nodes[1].reconsiderblock(self.nodes[0].getbestblockhash())

        # Now test the case where node1 has a transaction T in its mempool that
        # depends on transactions A and B which are in a mined block, and the
        # block containing A and B is disconnected, AND B is not accepted back
        # into node1's mempool because its ancestor count is too high.

        # Create 8 transactions, like so:
        # Tx0 -> Tx1 (vout0)
        #   \--> Tx2 (vout1) -> Tx3 -> Tx4 -> Tx5 -> Tx6 -> Tx7
        #
        # Mine them in the next block, then generate a new tx8 that spends
        # Tx1 and Tx7, and add to node1's mempool, then disconnect the
        # last block.

        # Create tx0 with 2 outputs
        utxo = self.nodes[0].listunspent()
        txid = utxo[0]['txid']
        value = utxo[0]['amount']
        vout = utxo[0]['vout']

        send_value = satoshi_round((value - fee)/2)
        inputs = [ {'txid' : txid, 'vout' : vout} ]
        outputs = {}
        for i in range(2):
            outputs[self.nodes[0].getnewaddress()] = send_value
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        signedtx = self.nodes[0].signrawtransaction(rawtx)
        txid = self.nodes[0].sendrawtransaction(signedtx['hex'])
        tx0_id = txid
        value = send_value

        # Create tx1
        tx1_id, _ = self.chain_transaction(self.nodes[0], tx0_id, 0, value, fee, 1)

        # Create tx2-7
        vout = 1
        txid = tx0_id
        for i in range(6):
            (txid, sent_value) = self.chain_transaction(self.nodes[0], txid, vout, value, fee, 1)
            vout = 0
            value = sent_value

        # Mine these in a block
        self.nodes[0].generate(1)
        self.sync_all()

        # Now generate tx8, with a big fee
        inputs = [ {'txid' : tx1_id, 'vout': 0}, {'txid' : txid, 'vout': 0} ]
        outputs = { self.nodes[0].getnewaddress() : send_value + value - 4*fee }
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        signedtx = self.nodes[0].signrawtransaction(rawtx)
        self.nodes[0].sendrawtransaction(signedtx['hex'])
        sync_mempools(self.nodes)
        
        # Now try to disconnect the tip on each node...
        self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())
        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
        sync_blocks(self.nodes)
Beispiel #19
0
 def fail_accept(self, node, error_msg, txid, sign, redeem_script=""):
     assert_raises_rpc_error(-26, error_msg, send_to_witness, 1, node,
                             getutxo(txid), self.pubkey[0], False,
                             Decimal("4999.8"), sign, redeem_script)
Beispiel #20
0
    def run_test(self):
        self.log.info("Mining 500 blocks...")
        self.nodes[0].generate(500)
        self.sync_all()

        assert_equal(self.nodes[1].getblockcount(), 500)
        assert_equal(self.nodes[1].getbalance(), 0)

        # Create and send two transactions
        tx1_in = self.nodes[0].listunspent().pop()
        tx1_out = tx1_in["amount"] - Decimal("0.01")
        tx1 = self.nodes[0].createrawtransaction([tx1_in], {self.nodes[1].getnewaddress(): tx1_out})
        txid1 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx1)["hex"])
        tx2_in = self.nodes[0].listunspent().pop()
        tx2_out = tx2_in["amount"] - Decimal("0.01")
        tx2 = self.nodes[0].createrawtransaction([tx2_in], {self.nodes[1].getnewaddress(): tx2_out})
        txid2 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx2)["hex"])

        # Try to get proof for one of the trasaction - should fail because transaction is not yet in a block
        assert_raises_rpc_error(-5, "Transaction not yet in block", self.nodes[0].getmerkleproof, txid1)
        assert_raises_rpc_error(-5, "Transaction not yet in block", self.nodes[0].getmerkleproof2, "", txid1)

        # Mine a new block
        self.log.info("Mining 501st block...")
        self.nodes[0].generate(1)
        self.sync_all()
        height_of_block_501 = self.nodes[1].getblockcount()

        # Check some negative tests on verifymerkleproof
        assert_raises_rpc_error(-8, "\"flags\" must be a numeric value", self.nodes[0].verifymerkleproof, {'flags': '2'})
        assert_raises_rpc_error(-8, "verifymerkleproof only supports \"flags\" with value 2", self.nodes[0].verifymerkleproof, {'flags': 1})
        assert_raises_rpc_error(-8, "\"nodes\" must be a Json array", self.nodes[0].verifymerkleproof, 
            {'flags':2,
             'index':4,
             'txOrId':'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
             'target':{'merkleroot':'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890'},
             'nodes':'*'})
        assert_raises_rpc_error(-8, "\"node\" must be a \"hash\" or \"*\"", self.nodes[0].verifymerkleproof, 
            {'flags':2,
             'index':4,
             'txOrId':'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
             'target':{'merkleroot':'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890'},
             'nodes':[2]})
        assert_raises_rpc_error(-8, "node must be of length 64 (not 10)", self.nodes[0].verifymerkleproof, 
            {'flags':2,
             'index':4,
             'txOrId':'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
             'target':{'merkleroot':'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890'},
             'nodes':['*','abcdef1234']})

        # Get proof for 1st and 2nd transaction and verify that calculated roots are the same as block's merkle root
        hash_of_block_501 = self.nodes[0].getblockhash(height_of_block_501)
        self.verify_merkle_proof(txid1, hash_of_block_501, 0)
        self.verify_merkle_proof(txid2, hash_of_block_501, 0)

        # Create and send 3rd transaction
        tx_spent = self.nodes[1].listunspent().pop()
        tx3_out = tx_spent["amount"] - Decimal("0.01")
        tx3 = self.nodes[1].createrawtransaction([tx_spent], {self.nodes[0].getnewaddress(): tx3_out})
        txid3 = self.nodes[0].sendrawtransaction(self.nodes[1].signrawtransaction(tx3)["hex"])

        # Mine a new block
        self.log.info("Mining 502nd block...")
        self.nodes[0].generate(1)
        self.sync_all()

        # Get id of spent and unspent transaction
        txid_spent = tx_spent["txid"]
        txid_unspent = txid1 if txid_spent != txid1 else txid2

        # We can't find the block if transaction was spent because -txindex is not set on node[0]
        assert_raises_rpc_error(-5, "Transaction not yet in block", self.nodes[0].getmerkleproof, txid_spent)
        assert_raises_rpc_error(-5, "Transaction not yet in block", self.nodes[0].getmerkleproof2, "", txid_spent)

        # We can get the proof if we specify proper block hash
        a = self.nodes[0].getmerkleproof(txid_spent, hash_of_block_501)
        b = self.nodes[0].getmerkleproof2(hash_of_block_501, txid_spent)
        assert self.nodes[0].verifymerkleproof(a)
        assert(self.check_equivalence(a,b))

        # We can't get the proof if we specify a non-existent block
        assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getmerkleproof,  txid_spent, "1234567890abcdef1234567890abcdef")
        assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getmerkleproof2,  "1234567890abcdef1234567890abcdef", txid_spent)

        # We can get the proof if the transaction is unspent
        self.verify_merkle_proof(txid_unspent, hash_of_block_501, 0)

        # We can get a proof of a spent transaction without block hash if node runs with -txindex (nodes[1] in this case)
        self.verify_merkle_proof(txid_spent, hash_of_block_501, 1)

        # Restart nodes
        self.log.info("Restarting nodes...")
        self.stop_nodes()
        self.start_nodes(self.extra_args)

        # Repeat tests after nodes restart
        self.verify_merkle_proof(txid_unspent, hash_of_block_501, 0)
        self.verify_merkle_proof(txid_spent, hash_of_block_501, 1)
        hash_of_block_502 = self.nodes[0].getblockhash(height_of_block_501 + 1)
        self.verify_merkle_proof(txid3, hash_of_block_502, 0)

        # Create more blocks to get utxos
        self.log.info("Mining additional 1500 blocks...")
        self.nodes[0].generate(1500)
        sync_blocks(self.nodes[0:1])

        # Use all utxos and create more Merkle Trees
        # We create blocks with max 400 transactions (~25 kB for biggest Merkle Tree)
        self.log.info("Mining blocks with random transactions using all utxos...")
        utxos = self.nodes[0].listunspent()
        calculated_merkle_tree_disk_size = 0
        verifyData = {}
        while len(utxos) > 0:
            # Choose random number of transactions
            send_transactions = random.randint(1, 400)
            if len(utxos) < send_transactions:
                send_transactions = len(utxos)
            # Send transactions
            for i in range(send_transactions):
                tx_in = utxos.pop()
                tx_out = tx_in["amount"] - Decimal("0.01")
                tx = self.nodes[0].createrawtransaction([tx_in], {self.nodes[1].getnewaddress(): tx_out})
                txid = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx)["hex"])
            # Mine a block
            self.nodes[0].generate(1)
            sync_blocks(self.nodes[0:1])
            # Verify proofs of some random transactions in each block
            hash_of_this_block = self.nodes[0].getblockhash(self.nodes[0].getblockcount())
            transactions_of_this_block = self.nodes[0].getblock(hash_of_this_block, True)["tx"]
            calculated_merkle_tree_disk_size += self.merkle_tree_size(len(transactions_of_this_block))
            verifyData[hash_of_this_block] = transactions_of_this_block
        # Verify merkle proofs of all transactions in all blocks
        self.verify_stored_data(verifyData, 0)
        
        # Data files checks
        number_of_data_files = 0
        disk_size = 0
        node0_data_dir = os.path.join(self.options.tmpdir, "node0", "regtest", "merkle", "")
        for data_file in os.listdir(node0_data_dir):
            data_file_name = node0_data_dir + data_file
            if os.path.isfile(data_file_name):
                data_file_size = os.path.getsize(data_file_name)
                # No file should be bigger than 30 kB since no Merkle Tree takes more than 25 kB
                assert_greater_than(30 * 1024, data_file_size)
                disk_size += data_file_size
                number_of_data_files += 1
        # Verify that Merkle Tree disk size is at least the size of Merkle Trees we just stored
        assert_greater_than(disk_size, calculated_merkle_tree_disk_size)
        # Number of data files should be at least calculated_merkle_tree_disk_size/preferred_file_size
        assert_greater_than(number_of_data_files, calculated_merkle_tree_disk_size/(30 * 1024))

        # Delete index to test recreation of index when node is started again
        self.log.info("Restarting nodes to remove Merkle Trees index...")
        self.stop_nodes()
        node0_index_dir = os.path.join(node0_data_dir, "index", "")
        shutil.rmtree(node0_index_dir)
        self.start_nodes(self.extra_args)
        # Repeat merkle proof checks
        self.verify_stored_data(verifyData, 0)
        # Since index was recreated from data files, requesting existing merkle trees shouldn't create any new data
        new_disk_size = 0
        for data_file in os.listdir(node0_data_dir):
            data_file_name = node0_data_dir + data_file
            if os.path.isfile(data_file_name):
                new_disk_size += os.path.getsize(data_file_name)
        assert_equal(disk_size, new_disk_size)
Beispiel #21
0
    def run_test(self):
        self.nodes[0].generate(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({})
        #         assert(tmpl['sizelimit'] == 1000000)
        #         assert('weightlimit' not in tmpl)
        #         assert(tmpl['sigoplimit'] == 20000)
        #         assert(tmpl['transactions'][0]['hash'] == txid)
        #         assert(tmpl['transactions'][0]['sigops'] == 2)
        #         tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']})
        #         assert(tmpl['sizelimit'] == 1000000)
        #         assert('weightlimit' not in tmpl)
        #         assert(tmpl['sigoplimit'] == 20000)
        #         assert(tmpl['transactions'][0]['hash'] == txid)
        #         assert(tmpl['transactions'][0]['sigops'] == 2)
        self.nodes[0].generate(1)  #block 162

        balance_presetup = self.nodes[0].getbalance()
        self.pubkey = []
        p2sh_ids = [
        ]  # p2sh_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE embedded in p2sh
        wit_ids = [
        ]  # wit_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE via bare witness
        for i in range(3):
            newaddress = self.nodes[i].getnewaddress()
            self.pubkey.append(
                self.nodes[i].validateaddress(newaddress)["pubkey"])
            multiaddress = self.nodes[i].addmultisigaddress(
                1, [self.pubkey[-1]])
            self.nodes[i].addwitnessaddress(newaddress)
            self.nodes[i].addwitnessaddress(multiaddress)
            p2sh_ids.append([])
            wit_ids.append([])
            for v in range(2):
                p2sh_ids[i].append([])
                wit_ids[i].append([])

        for i 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_unspent(self.nodes[0],
                                                     5000), self.pubkey[n],
                                        False, Decimal("4999.9")))
                    p2sh_ids[n][v].append(
                        send_to_witness(v, self.nodes[0],
                                        find_unspent(self.nodes[0],
                                                     5000), self.pubkey[n],
                                        True, Decimal("4999.9")))

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

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

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

        # unsigned, no scriptsig
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         wit_ids[NODE_0][WIT_V0][0], False)
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         wit_ids[NODE_0][WIT_V1][0], False)
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_0][WIT_V0][0], False)
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_0][WIT_V1][0], False)
        # unsigned with redeem script
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_0][WIT_V0][0], False,
                         witness_script(False, self.pubkey[0]))
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_0][WIT_V1][0], False,
                         witness_script(True, self.pubkey[0]))
        # signed
        #         self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V0][0], True)
        #         self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V1][0], True)
        #         self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V0][0], True)
        #         self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V1][0], True)

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

        # TODO: An old node would see these txs without witnesses and be able to mine them

        self.log.info(
            "Verify unsigned bare witness txs in versionbits-setting blocks are valid before the fork"
        )
        self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][1],
                          False)  #block 428
        self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][1],
                          False)  #block 429

        self.log.info(
            "Verify unsigned p2sh witness txs without a redeem script are invalid"
        )
        self.fail_accept(self.nodes[2], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_2][WIT_V0][1], False)
        self.fail_accept(self.nodes[2], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_2][WIT_V1][1], False)

        self.log.info(
            "Verify unsigned p2sh witness txs with a redeem script in versionbits-settings blocks are valid before the fork"
        )
        self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False,
                          witness_script(False, self.pubkey[2]))  #block 430
        self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False,
                          witness_script(True, self.pubkey[2]))  #block 431

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

        self.log.info(
            "Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag"
        )
        assert (self.nodes[2].getblock(block[0], False) !=
                self.nodes[0].getblock(block[0], False))
        assert (self.nodes[1].getblock(block[0],
                                       False) == self.nodes[2].getblock(
                                           block[0], False))
        for i in range(len(segwit_tx_list)):
            tx = from_hex(
                CTransaction(),
                self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
            assert (self.nodes[2].getrawtransaction(segwit_tx_list[i]) !=
                    self.nodes[0].getrawtransaction(segwit_tx_list[i]))
            assert (self.nodes[1].getrawtransaction(
                segwit_tx_list[i],
                0) == self.nodes[2].getrawtransaction(segwit_tx_list[i]))
            assert (self.nodes[0].getrawtransaction(segwit_tx_list[i]) !=
                    self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
            assert (self.nodes[1].getrawtransaction(
                segwit_tx_list[i]) == self.nodes[2].gettransaction(
                    segwit_tx_list[i])["hex"])
            assert (self.nodes[0].getrawtransaction(
                segwit_tx_list[i]) == bytes_to_hex_str(
                    tx.serialize_without_witness()))

        self.log.info(
            "Verify witness txs without witness data are invalid after the fork"
        )
        self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][2], False)
        self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][2], False)
        self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][2], False,
                       witness_script(False, self.pubkey[2]))
        self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][2], False,
                       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][WIT_V0][0],
                          True)  #block 432
        self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0],
                          True)  #block 433
        self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0],
                          True)  #block 434
        self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][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)
        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
        assert (
            tmpl['sizelimit'] >= 3999577
        )  # actual maximum size is lower due to minimum mandatory non-witness data
        assert (tmpl['weightlimit'] == 4000000)
        assert (tmpl['sigoplimit'] == 80000)
        assert (tmpl['transactions'][0]['txid'] == txid)
        assert (tmpl['transactions'][0]['sigops'] == 8)

        self.nodes[0].generate(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_unspent(self.nodes[0], 50),
                                self.pubkey[0], False, Decimal("49.996"))
        hex_tx = self.nodes[0].gettransaction(txid)['hex']
        tx = from_hex(CTransaction(), hex_tx)
        assert (tx.wit.is_null())  # This should not be a segwit input
        assert (txid1 in self.nodes[0].getrawmempool())

        # 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])))
        tx2_hex = self.nodes[0].signrawtransaction(to_hex(tx))['hex']
        txid2 = self.nodes[0].sendrawtransaction(tx2_hex)
        tx = from_hex(CTransaction(), tx2_hex)
        assert (not tx.wit.is_null())

        # 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])))  # Huge fee
        tx.calc_x16r()
        txid3 = self.nodes[0].sendrawtransaction(to_hex(tx))
        assert (tx.wit.is_null())
        assert (txid3 in self.nodes[0].getrawmempool())

        # Now try calling getblocktemplate() without segwit support.
        template = self.nodes[0].getblocktemplate()

        # Check that tx1 is the only transaction of the 3 in the template.
        template_txids = [t['txid'] for t in template['transactions']]
        assert (txid2 not in template_txids and txid3 not in template_txids)
        assert (txid1 in template_txids)

        # Check that running with segwit support results in all 3 being included.
        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 wtxid is properly reported in mempool entry
        assert_equal(int(self.nodes[0].getmempoolentry(txid3)["wtxid"], 16),
                     tx.calc_x16r(True))

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

        self.log.info(
            "Verify behaviour of importaddress, addwitnessaddress 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 (self.nodes[0].validateaddress(
            uncompressed_spendable_address[0])['iscompressed'] == False)
        assert (self.nodes[0].validateaddress(
            compressed_spendable_address[0])['iscompressed'] == True)

        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]
            ]))
        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2, [
                uncompressed_spendable_address[0],
                uncompressed_spendable_address[0]
            ]))
        compressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_spendable_address[0], compressed_spendable_address[0]
             ]))
        uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2, [
                compressed_spendable_address[0],
                uncompressed_solvable_address[0]
            ]))
        compressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_spendable_address[0], compressed_solvable_address[0]]))
        compressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_solvable_address[0], compressed_solvable_address[1]]))
        unknown_address = [
            "mtKKyoHabkk6e4ppT7NaM7THqPUt7AzPrT",
            "2NDP3jLWAFT8NDAiUa9qiE6oBt2awmMq7Dx"
        ]

        # 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]])
        script = CScript([
            OP_2,
            hex_str_to_bytes(pubkeys[3]),
            hex_str_to_bytes(pubkeys[4]), OP_2, OP_CHECKMULTISIG
        ])
        solvable_after_importaddress.append(
            CScript([OP_HASH160, hash160(script), OP_EQUAL]))

        for i in compressed_spendable_address:
            v = self.nodes[0].validateaddress(i)
            if v['isscript']:
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                # bare and p2sh multisig with compressed keys should always be spendable
                spendable_anytime.extend([bare, p2sh])
                # 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, and witness with compressed keys are spendable after direct importaddress
                spendable_after_importaddress.extend([
                    p2wpkh, p2sh_p2wpkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk,
                    p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ])

        for i in uncompressed_spendable_address:
            v = self.nodes[0].validateaddress(i)
            if v['isscript']:
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                # bare and p2sh multisig with uncompressed keys should always be spendable
                spendable_anytime.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 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 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].validateaddress(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 and P2PK with compressed keys should always be seen
                solvable_anytime.extend([p2pkh, p2pk])
                # P2SH_P2PK, P2SH_P2PKH, and witness with compressed keys are seen after direct importaddress
                solvable_after_importaddress.extend([
                    p2wpkh, p2sh_p2wpkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk,
                    p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ])

        for i in uncompressed_solvable_address:
            v = self.nodes[0].validateaddress(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 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 = [
            "mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V",
            "2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe",
            script_to_p2sh(op1),
            script_to_p2sh(op0)
        ]
        unsolvable_address_key = hex_str_to_bytes(
            "02341AEC7587A51CDE5279E0630A531AEA2615A9F80B17E8D9376327BAEAA59E3D"
        )
        unsolvablep2pkh = CScript([
            OP_DUP, OP_HASH160,
            hash160(unsolvable_address_key), OP_EQUALVERIFY, OP_CHECKSIG
        ])
        unsolvablep2wshp2pkh = CScript([OP_0, sha256(unsolvablep2pkh)])
        p2shop0 = CScript([OP_HASH160, hash160(op0), OP_EQUAL])
        p2wshop1 = CScript([OP_0, sha256(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].validateaddress(i)
            if v['isscript']:
                bare = hex_str_to_bytes(v['hex'])
                importlist.append(bytes_to_hex_str(bare))
                importlist.append(
                    bytes_to_hex_str(CScript([OP_0, sha256(bare)])))
            else:
                pubkey = hex_str_to_bytes(v['pubkey'])
                p2pk = CScript([pubkey, OP_CHECKSIG])
                p2pkh = CScript([
                    OP_DUP, OP_HASH160,
                    hash160(pubkey), OP_EQUALVERIFY, OP_CHECKSIG
                ])
                importlist.append(bytes_to_hex_str(p2pk))
                importlist.append(bytes_to_hex_str(p2pkh))
                importlist.append(
                    bytes_to_hex_str(CScript([OP_0, hash160(pubkey)])))
                importlist.append(
                    bytes_to_hex_str(CScript([OP_0, sha256(p2pk)])))
                importlist.append(
                    bytes_to_hex_str(CScript([OP_0, sha256(p2pkh)])))

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

        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)

        # addwitnessaddress should refuse to return a witness address if an uncompressed key is used
        # note that no witness address should be returned by unsolvable addresses
        for i in uncompressed_spendable_address + uncompressed_solvable_address + unknown_address + unsolvable_address:
            assert_raises_rpc_error(
                -4,
                "Public key or redeemscript not known to wallet, or the key is uncompressed",
                self.nodes[0].addwitnessaddress, i)

        # addwitnessaddress should return a witness addresses even if keys are not in the wallet
        self.nodes[0].addwitnessaddress(multisig_without_privkey_address)

        for i in compressed_spendable_address + compressed_solvable_address:
            witaddress = self.nodes[0].addwitnessaddress(i)
            # addwitnessaddress should return the same address if it is a known P2SH-witness address
            assert_equal(witaddress,
                         self.nodes[0].addwitnessaddress(witaddress))

        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])]

        spendable_after_addwitnessaddress = [
        ]  # These outputs should be seen after importaddress
        solvable_after_addwitnessaddress = [
        ]  # These outputs should be seen after importaddress but not spendable
        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]
            ]))
        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2, [
                uncompressed_spendable_address[0],
                uncompressed_spendable_address[0]
            ]))
        compressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_spendable_address[0], compressed_spendable_address[0]
             ]))
        uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_solvable_address[0], uncompressed_solvable_address[0]
             ]))
        compressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_spendable_address[0], compressed_solvable_address[0]]))

        premature_witaddress = []

        for i in compressed_spendable_address:
            v = self.nodes[0].validateaddress(i)
            if v['isscript']:
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after addwitnessaddress
                spendable_after_addwitnessaddress.extend([p2wsh, p2sh_p2wsh])
                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 spendable after addwitnessaddress
                spendable_after_addwitnessaddress.extend([p2wpkh, p2sh_p2wpkh])
                premature_witaddress.append(script_to_p2sh(p2wpkh))

        for i in uncompressed_spendable_address + uncompressed_solvable_address:
            v = self.nodes[0].validateaddress(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].validateaddress(i)
            if v['isscript']:
                # P2WSH multisig without private key are seen after addwitnessaddress
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                solvable_after_addwitnessaddress.extend([p2wsh, p2sh_p2wsh])
                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 seen after addwitnessaddress
                solvable_after_addwitnessaddress.extend([p2wpkh, p2sh_p2wpkh])
                premature_witaddress.append(script_to_p2sh(p2wpkh))

        self.mine_and_test_listunspent(
            spendable_after_addwitnessaddress +
            solvable_after_addwitnessaddress + unseen_anytime, 0)

        # addwitnessaddress should refuse to return a witness address if an uncompressed key is used
        # note that a multisig address returned by addmultisigaddress is not solvable until it is added with importaddress
        # premature_witaddress are not accepted until the script is added with addwitnessaddress first
        for i in uncompressed_spendable_address + uncompressed_solvable_address + premature_witaddress:
            # This will raise an exception
            assert_raises_rpc_error(
                -4,
                "Public key or redeemscript not known to wallet, or the key is uncompressed",
                self.nodes[0].addwitnessaddress, i)

        # after importaddress it should pass addwitnessaddress
        v = self.nodes[0].validateaddress(compressed_solvable_address[1])
        self.nodes[0].importaddress(v['hex'], "", False, True)
        for i in compressed_spendable_address + compressed_solvable_address + premature_witaddress:
            witaddress = self.nodes[0].addwitnessaddress(i)
            assert_equal(witaddress,
                         self.nodes[0].addwitnessaddress(witaddress))

        spendable_txid.append(
            self.mine_and_test_listunspent(spendable_after_addwitnessaddress,
                                           2))
        solvable_txid.append(
            self.mine_and_test_listunspent(solvable_after_addwitnessaddress,
                                           1))
        self.mine_and_test_listunspent(unseen_anytime, 0)

        # 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)
Beispiel #22
0
    def run_test(self):
        # Check that there's no UTXO on none of the nodes
        assert_equal(len(self.nodes[0].listunspent()), 0)
        assert_equal(len(self.nodes[1].listunspent()), 0)
        assert_equal(len(self.nodes[2].listunspent()), 0)

        self.log.info("Mining blocks...")

        self.nodes[0].generate(1)

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 250)
        assert_equal(walletinfo['balance'], 0)

        self.sync_all([self.nodes[0:3]])
        self.nodes[1].generate(101)
        self.sync_all([self.nodes[0:3]])

        assert_equal(self.nodes[0].getbalance(), 250)
        assert_equal(self.nodes[1].getbalance(), 250)
        assert_equal(self.nodes[2].getbalance(), 0)

        # Check that only first and second nodes have UTXOs
        utxos = self.nodes[0].listunspent()
        assert_equal(len(utxos), 1)
        assert_equal(len(self.nodes[1].listunspent()), 1)
        assert_equal(len(self.nodes[2].listunspent()), 0)

        # Send 21 SSS from 0 to 2 using sendtoaddress call.
        # Second transaction will be child of first, and will require a fee
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 21)
        #self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10)

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 0)

        # Have node0 mine a block, thus it will collect its own fee.
        self.nodes[0].generate(1)
        self.sync_all([self.nodes[0:3]])

        # Exercise locking of unspent outputs
        unspent_0 = self.nodes[2].listunspent()[0]
        unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]}
        self.nodes[2].lockunspent(False, [unspent_0])
        assert_raises_rpc_error(-4, "Insufficient funds",
                                self.nodes[2].sendtoaddress,
                                self.nodes[2].getnewaddress(), 20)
        assert_equal([unspent_0], self.nodes[2].listlockunspent())
        self.nodes[2].lockunspent(True, [unspent_0])
        assert_equal(len(self.nodes[2].listlockunspent()), 0)

        # Have node1 generate 100 blocks (so node0 can recover the fee)
        self.nodes[1].generate(100)
        self.sync_all([self.nodes[0:3]])

        # node0 should end up with 100 SSS in block rewards plus fees, but
        # minus the 21 plus fees sent to node2
        assert_equal(self.nodes[0].getbalance(), 500 - 21)
        assert_equal(self.nodes[2].getbalance(), 21)

        # Node0 should have two unspent outputs.
        # Create a couple of transactions to send them to node2, submit them through
        # node1, and make sure both node0 and node2 pick them up properly:
        node0utxos = self.nodes[0].listunspent(1)
        assert_equal(len(node0utxos), 2)

        # create both transactions
        txns_to_send = []
        for utxo in node0utxos:
            inputs = []
            outputs = {}
            inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]})
            outputs[self.nodes[2].getnewaddress("from1")] = float(
                utxo["amount"])
            raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
            txns_to_send.append(self.nodes[0].signrawtransaction(raw_tx))

        # Have node 1 (miner) send the transactions
        self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], True)
        self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], True)

        # Have node1 mine a block to confirm transactions:
        self.nodes[1].generate(1)
        self.sync_all([self.nodes[0:3]])

        assert_equal(self.nodes[0].getbalance(), 0)
        assert_equal(self.nodes[2].getbalance(), 500)
        assert_equal(self.nodes[2].getbalance("from1"), 500 - 21)

        # Send 10 SSS normal
        address = self.nodes[0].getnewaddress("test")
        fee_per_byte = Decimal('0.001') / 1000
        self.nodes[2].settxfee(float(fee_per_byte * 1000))
        txid = self.nodes[2].sendtoaddress(address, 10, "", "")
        fee = self.nodes[2].gettransaction(txid)["fee"]
        self.nodes[2].generate(1)
        self.sync_all([self.nodes[0:3]])
        node_2_bal = self.nodes[2].getbalance()
        assert_equal(self.nodes[0].getbalance(), Decimal('10'))

        # Send 10 SSS with subtract fee from amount
        txid = self.nodes[2].sendtoaddress(address, 10, "", "")
        self.nodes[2].generate(1)
        self.sync_all([self.nodes[0:3]])
        node_2_bal -= Decimal('10')
        assert_equal(self.nodes[2].getbalance() - fee, node_2_bal)
        node_0_bal = self.nodes[0].getbalance()
        assert_equal(node_0_bal, Decimal('20'))

        # Sendmany 10 SSS
        txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "")
        self.nodes[2].generate(1)
        self.sync_all([self.nodes[0:3]])
        node_0_bal += Decimal('10')
        node_2_bal -= Decimal('10')
        #node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid)))
        assert_equal(self.nodes[0].getbalance(), node_0_bal)

        # Sendmany 10 SSS with subtract fee from amount
        txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "")
        self.nodes[2].generate(1)
        self.sync_all([self.nodes[0:3]])
        node_2_bal -= Decimal('10')
        assert_equal(self.nodes[2].getbalance(), node_2_bal + (fee * 3))
        #node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid)))

        # Test ResendWalletTransactions:
        # Create a couple of transactions, then start up a fourth
        # node (nodes[3]) and ask nodes[0] to rebroadcast.
        # EXPECT: nodes[3] should have those transactions in its mempool.
        txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        sync_mempools(self.nodes[0:2])

        self.start_node(3)
        connect_nodes(self.nodes[0], 3)
        sync_blocks(self.nodes)

        # Exercise balance rpcs
        assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], 1)
        assert_equal(self.nodes[0].getunconfirmedbalance(), 1)

        #check if we can list zero value tx as available coins
        #1. create rawtx
        #2. hex-changed one output to 0.0
        #3. sign and send
        #4. check if recipient (node0) can list the zero value tx
        usp = self.nodes[1].listunspent()
        inputs = [{"txid": usp[0]['txid'], "vout": usp[0]['vout']}]
        outputs = {
            self.nodes[1].getnewaddress(): 49.998,
            self.nodes[0].getnewaddress(): 11.11
        }

        rawTx = self.nodes[1].createrawtransaction(inputs, outputs).replace(
            "c0833842", "00000000")  #replace 11.11 with 0.0 (int32)
        decRawTx = self.nodes[1].decoderawtransaction(rawTx)
        signedRawTx = self.nodes[1].signrawtransaction(rawTx)
        decRawTx = self.nodes[1].decoderawtransaction(signedRawTx['hex'])
        zeroValueTxid = decRawTx['txid']
        assert_raises_rpc_error(-25, "", self.nodes[1].sendrawtransaction,
                                signedRawTx['hex'])

        # This will raise an exception since generate does not accept a string
        assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate,
                                "2")

        # Import address and private key to check correct behavior of spendable unspents
        # 1. Send some coins to generate new UTXO
        address_to_import = self.nodes[2].getnewaddress()
        txid = self.nodes[0].sendtoaddress(address_to_import, 1)
        self.nodes[0].generate(1)
        self.sync_all([self.nodes[0:3]])

        # 2. Import address from node2 to node1
        self.nodes[1].importaddress(address_to_import)

        # 3. Validate that the imported address is watch-only on node1
        assert (
            self.nodes[1].validateaddress(address_to_import)["iswatchonly"])

        # 4. Check that the unspents after import are not spendable
        listunspent = self.nodes[1].listunspent(1, 9999999, [], 3)
        assert_array_result(listunspent, {"address": address_to_import},
                            {"spendable": False})

        # 5. Import private key of the previously imported address on node1
        priv_key = self.nodes[2].dumpprivkey(address_to_import)
        self.nodes[1].importprivkey(priv_key)

        # 6. Check that the unspents are now spendable on node1
        assert_array_result(self.nodes[1].listunspent(),
                            {"address": address_to_import},
                            {"spendable": True})

        #check if wallet or blochchain maintenance changes the balance
        self.sync_all([self.nodes[0:3]])
        blocks = self.nodes[0].generate(2)
        self.sync_all([self.nodes[0:3]])
        balance_nodes = [self.nodes[i].getbalance() for i in range(3)]
        block_count = self.nodes[0].getblockcount()

        maintenance = [
            '-rescan',
            '-reindex',
            '-zapwallettxes=1',
            '-zapwallettxes=2',
            #'-salvagewallet',
        ]
        chainlimit = 6
        for m in maintenance:
            self.log.info("check " + m)
            self.stop_nodes()
            # set lower ancestor limit for later
            self.start_node(0, [m, "-limitancestorcount=" + str(chainlimit)])
            self.start_node(1, [m, "-limitancestorcount=" + str(chainlimit)])
            self.start_node(2, [m, "-limitancestorcount=" + str(chainlimit)])
            if m == '-reindex':
                # reindex will leave rpc warm up "early"; Wait for it to finish
                wait_until(lambda: [block_count] * 3 ==
                           [self.nodes[i].getblockcount() for i in range(3)])
            assert_equal(balance_nodes,
                         [self.nodes[i].getbalance() for i in range(3)])

        # Exercise listsinceblock with the last two blocks
        coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0])
        assert_equal(coinbase_tx_1["lastblock"], blocks[1])
        assert_equal(len(coinbase_tx_1["transactions"]), 1)
        assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1])
        assert_equal(
            len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0)
    def run_test(self):

        #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()

        # 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()
        assert_raises_rpc_error(-3, "Expected type object", self.nodes[0].createrawtransaction, [], 'foo')
        #assert_raises_rpc_error(-8, "Data must be hexadecimal string", self.nodes[0].createrawtransaction, [], {'data': 'foo'})
        assert_raises_rpc_error(-5, "Invalid PIVX address", self.nodes[0].createrawtransaction, [], {'foo': 0})
        #assert_raises_rpc_error(-3, "Amount is not a number", 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)]))

        # 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)
        addr = self.nodes[0].getnewaddress("")
        addrinfo = self.nodes[0].validateaddress(addr)
        pubkey = addrinfo["scriptPubKey"]

        self.log.info('sendrawtransaction with missing prevtx info')

        # Test `signrawtransaction` 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].signrawtransaction(rawtx, [prevtx])
        assert succ["complete"]
        del prevtx["amount"]
        succ = self.nodes[0].signrawtransaction(rawtx, [prevtx])
        assert succ["complete"]
        assert_raises_rpc_error(-3, "Missing vout", self.nodes[0].signrawtransaction, rawtx, [
            {
                "txid": txid,
                "scriptPubKey": pubkey,
                "amount": 1,
            }
        ])
        assert_raises_rpc_error(-3, "Missing txid", self.nodes[0].signrawtransaction, rawtx, [
            {
                "scriptPubKey": pubkey,
                "vout": 3,
                "amount": 1,
            }
        ])
        assert_raises_rpc_error(-3, "Missing scriptPubKey", self.nodes[0].signrawtransaction, rawtx, [
            {
                "txid": txid,
                "vout": 3,
                "amount": 1
            }
        ])

        #########################################
        # 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].signrawtransaction(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(tx, True, 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].validateaddress(addr1)
        addr2Obj = self.nodes[2].validateaddress(addr2)

        # Tests for createmultisig and addmultisigaddress
        assert_raises_rpc_error(-1, "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(-1, "no full public key for address", self.nodes[0].createmultisig, 2, [addr1Obj['pubkey'], addr1])

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

        #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].validateaddress(addr1)
        addr2Obj = self.nodes[2].validateaddress(addr2)
        addr3Obj = self.nodes[2].validateaddress(addr3)

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

        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 A 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']}]
        outputs = { self.nodes[0].getnewaddress() : 2.19 }
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned = self.nodes[1].signrawtransaction(rawTx, inputs)
        assert_equal(rawTxPartialSigned['complete'], False) #node1 only has one key, can't comp. sign the tx

        rawTxSigned = self.nodes[2].signrawtransaction(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('250.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].validateaddress(addr1)
        addr2Obj = self.nodes[2].validateaddress(addr2)

        self.nodes[1].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])
        mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])
        mSigObjValid = self.nodes[2].validateaddress(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].signrawtransaction(rawTx2, inputs)
        self.log.info(rawTxPartialSigned1)
        assert_equal(rawTxPartialSigned['complete'], False) #node1 only has one key, can't comp. sign the tx

        rawTxPartialSigned2 = self.nodes[2].signrawtransaction(rawTx2, inputs)
        self.log.info(rawTxPartialSigned2)
        assert_equal(rawTxPartialSigned2['complete'], False) #node2 only has one key, can't comp. sign the tx

        rawTxSignedComplete = self.nodes[2].signrawtransaction(rawTxPartialSigned1['hex'], inputs)
        self.log.info(rawTxSignedComplete)
        assert_equal(rawTxSignedComplete['complete'], True)
        self.nodes[2].sendrawtransaction(rawTxSignedComplete['hex'])
        rawTx2 = self.nodes[0].decoderawtransaction(rawTxSignedComplete['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal+Decimal('250.00000000')+Decimal('2.19000000')) #block reward + tx

        # decoderawtransaction tests
        encrawtx = "01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000"
        decrawtx = self.nodes[0].decoderawtransaction(encrawtx) # decode as non-witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))

        # getrawtransaction tests
        # 1. valid parameters - only supply txid
        txHash = rawTx["txid"]
        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'])

        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)
Beispiel #24
0
    def run_test(self):
        chain_height = self.nodes[0].getblockcount()
        assert_equal(chain_height, 200)

        self.log.debug("Mine a single block to get out of IBD")
        self.nodes[0].generate(1)
        self.sync_all()

        self.log.debug("Send 5 transactions from node2 (to its own address)")
        for _ in range(5):
            self.nodes[2].sendtoaddress(self.nodes[2].getnewaddress(),
                                        Decimal("10"))
        self.sync_all()

        self.log.debug(
            "Verify that node0 and node1 have 5 transactions in their mempools"
        )
        assert_equal(len(self.nodes[0].getrawmempool()), 5)
        assert_equal(len(self.nodes[1].getrawmempool()), 5)

        self.log.debug(
            "Stop-start node0 and node1. Verify that node0 has the transactions in its mempool and node1 does not."
        )
        self.stop_nodes()
        self.start_node(0)
        self.start_node(1)
        # Give mulecoind a second to reload the mempool
        time.sleep(1)
        wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5,
                   err_msg="Wait for getRawMempool")
        assert_equal(len(self.nodes[1].getrawmempool()), 0)

        self.log.debug(
            "Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file."
        )
        self.stop_nodes()
        self.start_node(0, extra_args=["-persistmempool=0"])
        # Give mulecoind a second to reload the mempool
        time.sleep(1)
        assert_equal(len(self.nodes[0].getrawmempool()), 0)

        self.log.debug(
            "Stop-start node0. Verify that it has the transactions in its mempool."
        )
        self.stop_nodes()
        self.start_node(0)
        wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5,
                   err_msg="Wait for getRawMempool")

        mempooldat0 = os.path.join(self.options.tmpdir, 'node0', 'regtest',
                                   'mempool.dat')
        mempooldat1 = os.path.join(self.options.tmpdir, 'node1', 'regtest',
                                   'mempool.dat')
        self.log.debug(
            "Remove the mempool.dat file. Verify that savemempool to disk via RPC re-creates it"
        )
        os.remove(mempooldat0)
        self.nodes[0].savemempool()
        assert os.path.isfile(mempooldat0)

        self.log.debug(
            "Stop nodes, make node1 use mempool.dat from node0. Verify it has 5 transactions"
        )
        os.rename(mempooldat0, mempooldat1)
        self.stop_nodes()
        self.start_node(1, extra_args=[])
        wait_until(lambda: len(self.nodes[1].getrawmempool()) == 5,
                   err_msg="Wait for getRawMempool")

        self.log.debug(
            "Prevent mulecoind from writing mempool.dat to disk. Verify that `savemempool` fails"
        )
        # to test the exception we are setting bad permissions on a tmp file called mempool.dat.new
        # which is an implementation detail that could change and break this test
        mempooldotnew1 = mempooldat1 + '.new'
        with os.fdopen(os.open(mempooldotnew1, os.O_CREAT, 0o000), 'w'):
            pass
        assert_raises_rpc_error(-1, "Unable to dump mempool to disk",
                                self.nodes[1].savemempool)
        os.remove(mempooldotnew1)
    def run_test(self):

        #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()

        #########################################
        # 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].signrawtransaction(rawtx)

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

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

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

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

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

        # send 1.2 RVN to msig adr
        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].validateaddress(addr1)
        addr2Obj = self.nodes[2].validateaddress(addr2)
        addr3Obj = self.nodes[2].validateaddress(addr3)

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

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

        #THIS IS A 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']
        }]
        outputs = {self.nodes[0].getnewaddress(): 2.19}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned = self.nodes[1].signrawtransaction(rawTx, inputs)
        assert_equal(rawTxPartialSigned['complete'],
                     False)  #node1 only has one key, can't comp. sign the tx

        rawTxSigned = self.nodes[2].signrawtransaction(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('5000.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].validateaddress(addr1)
        addr2Obj = self.nodes[2].validateaddress(addr2)

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

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        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']
        }]
        outputs = {self.nodes[0].getnewaddress(): 2.19}
        rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned1 = self.nodes[1].signrawtransaction(rawTx2, inputs)
        self.log.debug(rawTxPartialSigned1)
        assert_equal(rawTxPartialSigned['complete'],
                     False)  #node1 only has one key, can't comp. sign the tx

        rawTxPartialSigned2 = self.nodes[2].signrawtransaction(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)
        self.nodes[0].decoderawtransaction(rawTxComb)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(),
                     bal + Decimal('5000.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(-3, "Invalid type",
                                self.nodes[0].getrawtransaction, txHash,
                                "Flase")

        # 7. invalid parameters - supply txid and empty array
        assert_raises_rpc_error(-3, "Invalid type",
                                self.nodes[0].getrawtransaction, txHash, [])

        # 8. invalid parameters - supply txid and empty dict
        assert_raises_rpc_error(-3, "Invalid type",
                                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)
        dec_raw_tx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(dec_raw_tx['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)
        dec_raw_tx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(dec_raw_tx['vin'][0]['sequence'], 4294967294)
 def test_simple_one_coin(self):
     self.log.info("simple test with one coin")
     dec_tx, fee, changepos = self.create_and_fund(2, [], {self.nodes[0].getnewaddress(): 2.6})
     assert_equal(len(dec_tx['vin']) > 0, True)              # test if we have enought inputs
     assert_greater_than(changepos, -1)                      # check change
     assert_equal(Decimal(dec_tx['vout'][changepos]['value']) + fee, DecimalAmt(2.4))
Beispiel #27
0
def satoshi_round(amount):
    return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
Beispiel #28
0
def test_non_rbf_bumpfee_fails(peer_node, dest_address):
    # cannot replace a non RBF transaction (from node which did not enable RBF)
    not_rbf_id = peer_node.sendtoaddress(dest_address, Decimal("0.00090000"))
    assert_raises_rpc_error(-4, "not BIP 125 replaceable", peer_node.bumpfee,
                            not_rbf_id)
Beispiel #29
0
    def run_test(self):
        # Check that there's no UTXO on none of the nodes
        assert_equal(len(self.nodes[0].listunspent()), 0)
        assert_equal(len(self.nodes[1].listunspent()), 0)
        assert_equal(len(self.nodes[2].listunspent()), 0)

        self.log.info("Mining blocks...")

        self.nodes[0].generate(1)

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 250)
        assert_equal(walletinfo['balance'], 0)

        self.sync_all([self.nodes[0:3]])
        self.nodes[1].generate(101)
        self.sync_all([self.nodes[0:3]])

        assert_equal(self.nodes[0].getbalance(), 250)
        assert_equal(self.nodes[1].getbalance(), 250)
        assert_equal(self.nodes[2].getbalance(), 0)

        # Check that only first and second nodes have UTXOs
        utxos = self.nodes[0].listunspent()
        assert_equal(len(utxos), 1)
        assert_equal(len(self.nodes[1].listunspent()), 1)
        assert_equal(len(self.nodes[2].listunspent()), 0)

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 0)

        # Exercise locking of unspent outputs
        unspent_0 = self.nodes[1].listunspent()[0]
        unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]}
        self.nodes[1].lockunspent(False, [unspent_0])
        assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[1].sendtoaddress, self.nodes[1].getnewaddress(), 20)
        assert_equal([unspent_0], self.nodes[1].listlockunspent())
        self.nodes[1].lockunspent(True, [unspent_0])
        assert_equal(len(self.nodes[1].listlockunspent()), 0)

        # Send 21 YEP from 1 to 0 using sendtoaddress call.
        self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 21)
        self.nodes[1].generate(1)
        self.sync_all([self.nodes[0:3]])

        # Node0 should have two unspent outputs.
        # Create a couple of transactions to send them to node2, submit them through
        # node1, and make sure both node0 and node2 pick them up properly:
        node0utxos = self.nodes[0].listunspent(1)
        assert_equal(len(node0utxos), 2)

        # create both transactions
        fee_per_kbyte = Decimal('0.001')
        txns_to_send = []
        for utxo in node0utxos:
            inputs = []
            outputs = {}
            inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]})
            outputs[self.nodes[2].getnewaddress()] = float(utxo["amount"]) - float(fee_per_kbyte)
            raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
            txns_to_send.append(self.nodes[0].signrawtransaction(raw_tx))

        # Have node 1 (miner) send the transactions
        self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], True)
        self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], True)

        # Have node1 mine a block to confirm transactions:
        self.nodes[1].generate(1)
        self.sync_all([self.nodes[0:3]])

        assert_equal(self.nodes[0].getbalance(), 0)
        node_2_expected_bal = Decimal('250') + Decimal('21') - 2 * fee_per_kbyte
        node_2_bal = self.nodes[2].getbalance()
        assert_equal(node_2_bal, node_2_expected_bal)

        # Send 10 YEP normal
        address = self.nodes[0].getnewaddress("test")
        self.nodes[2].settxfee(float(fee_per_kbyte))
        txid = self.nodes[2].sendtoaddress(address, 10, "", "")
        fee = self.nodes[2].gettransaction(txid)["fee"]
        node_2_bal -= (Decimal('10') - fee)
        assert_equal(self.nodes[2].getbalance(), node_2_bal)
        self.nodes[2].generate(1)
        self.sync_all([self.nodes[0:3]])
        node_0_bal = self.nodes[0].getbalance()
        assert_equal(node_0_bal, Decimal('10'))

        # Sendmany 10 YEP
        txid = self.nodes[2].sendmany('', {address: 10}, 0, "")
        fee = self.nodes[2].gettransaction(txid)["fee"]
        self.nodes[2].generate(1)
        self.sync_all([self.nodes[0:3]])
        node_0_bal += Decimal('10')
        node_2_bal -= (Decimal('10') - fee)
        assert_equal(self.nodes[2].getbalance(), node_2_bal)
        assert_equal(self.nodes[0].getbalance(), node_0_bal)
        assert_fee_amount(-fee, self.get_vsize(self.nodes[2].getrawtransaction(txid)), fee_per_kbyte)

        # This will raise an exception since generate does not accept a string
        assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2")

        # Import address and private key to check correct behavior of spendable unspents
        # 1. Send some coins to generate new UTXO
        address_to_import = self.nodes[2].getnewaddress()
        self.nodes[0].sendtoaddress(address_to_import, 1)
        self.nodes[0].generate(1)
        self.sync_all([self.nodes[0:3]])

        # 2. Import address from node2 to node1
        self.nodes[1].importaddress(address_to_import)

        # 3. Validate that the imported address is watch-only on node1
        assert(self.nodes[1].validateaddress(address_to_import)["iswatchonly"])

        # 4. Check that the unspents after import are not spendable
        listunspent = self.nodes[1].listunspent(1, 9999999, [], 2)
        assert_array_result(listunspent,
                           {"address": address_to_import},
                           {"spendable": False})

        # 5. Import private key of the previously imported address on node1
        priv_key = self.nodes[2].dumpprivkey(address_to_import)
        self.nodes[1].importprivkey(priv_key)

        # 6. Check that the unspents are now spendable on node1
        assert_array_result(self.nodes[1].listunspent(),
                           {"address": address_to_import},
                           {"spendable": True})

        # check if wallet or blochchain maintenance changes the balance
        self.sync_all([self.nodes[0:3]])
        blocks = self.nodes[0].generate(2)
        self.sync_all([self.nodes[0:3]])
        balance_nodes = [self.nodes[i].getbalance() for i in range(3)]
        block_count = self.nodes[0].getblockcount()

        maintenance = [
            '-rescan',
            '-reindex',
        ]
        for m in maintenance:
            self.log.info("check " + m)
            self.stop_nodes()
            # set lower ancestor limit for later
            self.start_node(0, [m])
            self.start_node(1, [m])
            self.start_node(2, [m])
            if m == '-reindex':
                # reindex will leave rpc warm up "early"; Wait for it to finish
                wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)])
            assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)])

        # Exercise listsinceblock with the last two blocks
        coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0])
        assert_equal(coinbase_tx_1["lastblock"], blocks[1])
        assert_equal(len(coinbase_tx_1["transactions"]), 1)
        assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1])
        assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0)
    def run_test(self):
        self.nodes[0].generate(5)
        sync_blocks(self.nodes)
        self.nodes[1].generate(110)
        sync_blocks(self.nodes)
        balance = self.nodes[0].getbalance()
        txA = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 10)
        txB = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 10)
        txC = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 10)
        sync_mempools(self.nodes)
        self.nodes[1].generate(1)

        sync_blocks(self.nodes)
        newbalance = self.nodes[0].getbalance()
        assert(balance - newbalance < Decimal("0.001")) #no more than fees lost
        balance = newbalance

        # Disconnect nodes so node0's transactions don't get into node1's mempool
        disconnect_nodes(self.nodes[0], 1)

        # Identify the 10btc outputs
        nA = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txA, 1)["vout"]) if vout["value"] == 10)
        nB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txB, 1)["vout"]) if vout["value"] == 10)
        nC = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txC, 1)["vout"]) if vout["value"] == 10)

        inputs =[]
        # spend 10btc outputs from txA and txB
        inputs.append({"txid":txA, "vout":nA})
        inputs.append({"txid":txB, "vout":nB})
        outputs = {}

        outputs[self.nodes[0].getnewaddress()] = 14.99998
        outputs[self.nodes[1].getnewaddress()] = 5
        signed = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs))
        txAB1 = self.nodes[0].sendrawtransaction(signed["hex"])

        # Identify the 14.99998btc output
        nAB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txAB1, 1)["vout"]) if vout["value"] == Decimal("14.99998"))

        #Create a child tx spending AB1 and C
        inputs = []
        inputs.append({"txid":txAB1, "vout":nAB})
        inputs.append({"txid":txC, "vout":nC})
        outputs = {}
        outputs[self.nodes[0].getnewaddress()] = 24.9996
        signed2 = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs))
        txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"])

        # Create a child tx spending ABC2
        inputs = []
        inputs.append({"txid":txABC2, "vout":0})
        outputs = {}
        outputs[self.nodes[0].getnewaddress()] = 24.999
        signed3 = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs))
        # note tx is never directly referenced, only abandoned as a child of the above
        self.nodes[0].sendrawtransaction(signed3["hex"])

        # In mempool txs from self should increase balance from change
        newbalance = self.nodes[0].getbalance()
        assert_equal(newbalance, Decimal(round(balance - Decimal("30") + Decimal(24.999), 8)))
        balance = newbalance

        # Restart the node with a higher min relay fee so the parent tx is no longer in mempool
        # TODO: redo with eviction
        # Note had to make sure tx did not have AllowFree priority
        self.stop_node(0)
        self.start_node(0, extra_args=["-minrelaytxfee=0.0001"])

        # Verify txs no longer in mempool
        assert_equal(len(self.nodes[0].getrawmempool()), 0)

        # Not in mempool txs from self should only reduce balance
        # inputs are still spent, but change not received
        newbalance = self.nodes[0].getbalance()
        assert_equal(newbalance, balance - Decimal("24.999"))
        # Unconfirmed received funds that are not in mempool, also shouldn't show
        # up in unconfirmed balance
        unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance()
        assert_equal(unconfbalance, newbalance)
        # Also shouldn't show up in listunspent
        assert(not txABC2 in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)])
        balance = newbalance

        # Abandon original transaction and verify inputs are available again
        # including that the child tx was also abandoned
        self.nodes[0].abandontransaction(txAB1)
        newbalance = self.nodes[0].getbalance()
        assert_equal(newbalance, balance + Decimal("30"))
        balance = newbalance

        # Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned
        self.stop_node(0)
        self.start_node(0, extra_args=["-minrelaytxfee=0.00001"])
        assert_equal(len(self.nodes[0].getrawmempool()), 0)
        assert_equal(self.nodes[0].getbalance(), balance)

        # But if its received again then it is unabandoned
        # And since now in mempool, the change is available
        # But its child tx remains abandoned
        self.nodes[0].sendrawtransaction(signed["hex"])
        newbalance = self.nodes[0].getbalance()
        assert_equal(newbalance, balance - Decimal("20") + Decimal("14.99998"))
        balance = newbalance

        # Send child tx again so its unabandoned
        self.nodes[0].sendrawtransaction(signed2["hex"])
        newbalance = self.nodes[0].getbalance()
        assert_equal(newbalance, balance - Decimal("10") - Decimal("14.99998") + Decimal("24.9996"))
        balance = newbalance

        # Remove using high relay fee again
        self.stop_node(0)
        self.start_node(0, extra_args=["-minrelaytxfee=0.0001"])
        assert_equal(len(self.nodes[0].getrawmempool()), 0)
        newbalance = self.nodes[0].getbalance()
        assert_equal(newbalance, balance - Decimal("24.9996"))
        balance = newbalance

        # Create a double spend of AB1 by spending again from only A's 10 output
        # Mine double spend from node 1
        inputs =[]
        inputs.append({"txid":txA, "vout":nA})
        outputs = {}
        outputs[self.nodes[1].getnewaddress()] = 9.9999
        tx = self.nodes[0].createrawtransaction(inputs, outputs)
        signed = self.nodes[0].signrawtransaction(tx)
        self.nodes[1].sendrawtransaction(signed["hex"])
        self.nodes[1].generate(1)

        connect_nodes(self.nodes[0], 1)
        sync_blocks(self.nodes)

        # Verify that B and C's 10 BTC outputs are available for spending again because AB1 is now conflicted
        newbalance = self.nodes[0].getbalance()
        #assert_equal(newbalance, balance + Decimal("20"))
        balance = newbalance

        # There is currently a minor bug around this and so this test doesn't work.  See Issue #7315
        # Invalidate the block with the double spend and B's 10 BTC output should no longer be available
        # Don't think C's should either
        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
        newbalance = self.nodes[0].getbalance()
        #assert_equal(newbalance, balance - Decimal("10"))
        print("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer")
        print("conflicted has not resumed causing its inputs to be seen as spent.  See Issue #7315")
        print(str(balance) + " -> " + str(newbalance) + " ?")