예제 #1
0
    def test_getpeerinfo(self):
        self.log.info("Test getpeerinfo")
        # Create a few getpeerinfo last_block/last_transaction values.
        if self.is_wallet_compiled():
            self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        self.nodes[1].generate(1)
        self.sync_all()
        time_now = int(time.time())
        peer_info = [x.getpeerinfo() for x in self.nodes]
        # Verify last_block and last_transaction keys/values.
        for node, peer, field in product(range(self.num_nodes), range(2),
                                         ['last_block', 'last_transaction']):
            assert field in peer_info[node][peer].keys()
            if peer_info[node][peer][field] != 0:
                assert_approx(peer_info[node][peer][field], time_now, vspan=60)
        # check both sides of bidirectional connection between nodes
        # the address bound to on one side will be the source address for the other node
        assert_equal(peer_info[0][0]['addrbind'], peer_info[1][0]['addr'])
        assert_equal(peer_info[1][0]['addrbind'], peer_info[0][0]['addr'])
        assert_equal(peer_info[0][0]['minfeefilter'], Decimal("0.00000500"))
        assert_equal(peer_info[1][0]['minfeefilter'], Decimal("0.00001000"))
        # check the `servicesnames` field
        for info in peer_info:
            assert_net_servicesnames(int(info[0]["services"], 0x10),
                                     info[0]["servicesnames"])

        assert_equal(peer_info[0][0]['connection_type'], 'inbound')
        assert_equal(peer_info[0][1]['connection_type'], 'manual')

        assert_equal(peer_info[1][0]['connection_type'], 'manual')
        assert_equal(peer_info[1][1]['connection_type'], 'inbound')
예제 #2
0
파일: rpc_net.py 프로젝트: syscoin/syscoin
    def test_getpeerinfo(self):
        self.log.info("Test getpeerinfo")
        # Create a few getpeerinfo last_block/last_transaction values.
        self.wallet.send_self_transfer(
            from_node=self.nodes[0]
        )  # Make a transaction so we can see it in the getpeerinfo results
        self.generate(self.nodes[1], 1)
        time_now = int(time.time())
        peer_info = [x.getpeerinfo() for x in self.nodes]
        # Verify last_block and last_transaction keys/values.
        for node, peer, field in product(range(self.num_nodes), range(2),
                                         ['last_block', 'last_transaction']):
            assert field in peer_info[node][peer].keys()
            if peer_info[node][peer][field] != 0:
                assert_approx(peer_info[node][peer][field], time_now, vspan=60)
        # check both sides of bidirectional connection between nodes
        # the address bound to on one side will be the source address for the other node
        assert_equal(peer_info[0][0]['addrbind'], peer_info[1][0]['addr'])
        assert_equal(peer_info[1][0]['addrbind'], peer_info[0][0]['addr'])
        assert_equal(peer_info[0][0]['minfeefilter'], Decimal("0.00000500"))
        assert_equal(peer_info[1][0]['minfeefilter'], Decimal("0.00001000"))
        # check the `servicesnames` field
        for info in peer_info:
            assert_net_servicesnames(int(info[0]["services"], 0x10),
                                     info[0]["servicesnames"])

        assert_equal(peer_info[0][0]['connection_type'], 'inbound')
        assert_equal(peer_info[0][1]['connection_type'], 'manual')

        assert_equal(peer_info[1][0]['connection_type'], 'manual')
        assert_equal(peer_info[1][1]['connection_type'], 'inbound')

        # Check dynamically generated networks list in getpeerinfo help output.
        assert "(ipv4, ipv6, onion, i2p, cjdns, not_publicly_routable)" in self.nodes[
            0].help("getpeerinfo")
예제 #3
0
 def _check_psbt(psbt, to, value, multisig):
     """Helper function for any of the N participants to check the psbt with decodepsbt and verify it is OK before signing."""
     tx = multisig.decodepsbt(psbt)["tx"]
     amount = 0
     for vout in tx["vout"]:
         address = vout["scriptPubKey"]["address"]
         assert_equal(multisig.getaddressinfo(address)["ischange"], address != to)
         if address == to:
             amount += vout["value"]
     assert_approx(amount, float(value), vspan=0.001)
예제 #4
0
def assert_unspent(node, total_count=None, total_sum=None, reused_supported=None, reused_count=None, reused_sum=None):
    '''Make assertions about a node's unspent output statistics'''
    stats = count_unspent(node)
    if total_count is not None:
        assert_equal(stats["total"]["count"], total_count)
    if total_sum is not None:
        assert_approx(stats["total"]["sum"], total_sum, 0.001)
    if reused_supported is not None:
        assert_equal(stats["reused"]["supported"], reused_supported)
    if reused_count is not None:
        assert_equal(stats["reused"]["count"], reused_count)
    if reused_sum is not None:
        assert_approx(stats["reused"]["sum"], reused_sum, 0.001)
예제 #5
0
    def test_sending_from_reused_address_without_avoid_reuse(self):
        '''
        Test the same as test_sending_from_reused_address_fails, except send the 10 ECC with
        the avoid_reuse flag set to false. This means the 10 ECC send should succeed,
        where it fails in test_sending_from_reused_address_fails.
        '''
        self.log.info("Test sending from reused address with avoid_reuse=false")

        fundaddr = self.nodes[1].getnewaddress()
        retaddr = self.nodes[0].getnewaddress()

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 10 ecc output
        assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0)
        # getbalances should show no used, 10 ecc trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})
        # node 0 should not show a used entry, as it does not enable avoid_reuse
        assert("used" not in self.nodes[0].getbalances()["mine"])

        self.nodes[1].sendtoaddress(retaddr, 5)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 5 ecc output
        assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0)
        # getbalances should show no used, 5 ecc trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 2 total outputs (5, 10 ecc), one unused (5), one reused (10)
        assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
        # getbalances should show 10 used, 5 ecc trusted
        assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5})

        self.nodes[1].sendtoaddress(address=retaddr, amount=10, avoid_reuse=False)

        # listunspent should show 1 total outputs (5 ecc), unused
        assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_count=0)
        # getbalances should show no used, 5 ecc trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})

        # node 1 should now have about 5 ecc left (for both cases)
        assert_approx(self.nodes[1].getbalance(), 5, 0.001)
        assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 5, 0.001)
예제 #6
0
    def test_fund_send_fund_send(self):
        '''
        Test the simple case where [1] generates a new address A, then
        [0] sends 10 DIAZ to A.
        [1] spends 5 DIAZ from A. (leaving roughly 5 DIAZ useable)
        [0] sends 10 DIAZ to A again.
        [1] tries to spend 10 DIAZ (fails; dirty).
        [1] tries to spend 4 DIAZ (succeeds; change address sufficient)
        '''
        self.log.info("Test fund send fund send")

        fundaddr = self.nodes[1].getnewaddress()
        retaddr = self.nodes[0].getnewaddress()

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 10 diaz output
        assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0)
        # getbalances should show no used, 10 diaz trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})

        self.nodes[1].sendtoaddress(retaddr, 5)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 5 diaz output
        assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0)
        # getbalances should show no used, 5 diaz trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 2 total outputs (5, 10 diaz), one unused (5), one reused (10)
        assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
        # getbalances should show 10 used, 5 diaz trusted
        assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5})

        # node 1 should now have a balance of 5 (no dirty) or 15 (including dirty)
        assert_approx(self.nodes[1].getbalance(), 5, 0.001)
        assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 15, 0.001)

        assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[1].sendtoaddress, retaddr, 10)

        self.nodes[1].sendtoaddress(retaddr, 4)

        # listunspent should show 2 total outputs (1, 10 diaz), one unused (1), one reused (10)
        assert_unspent(self.nodes[1], total_count=2, total_sum=11, reused_count=1, reused_sum=10)
        # getbalances should show 10 used, 1 diaz trusted
        assert_balances(self.nodes[1], mine={"used": 10, "trusted": 1})

        # node 1 should now have about 1 diaz left (no dirty) and 11 (including dirty)
        assert_approx(self.nodes[1].getbalance(), 1, 0.001)
        assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 11, 0.001)
예제 #7
0
    def test_getpeerinfo(self):
        self.log.info("Test getpeerinfo")
        # Create a few getpeerinfo last_block/last_transaction/last_proof
        # values.
        if self.is_wallet_compiled():
            self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1000000)
        tip = self.nodes[1].generate(1)[0]
        self.sync_all()

        stake = create_coinbase_stakes(
            self.nodes[1], [tip],
            self.nodes[1].get_deterministic_priv_key().key)
        privkey = ECKey()
        privkey.generate()
        proof = self.nodes[1].buildavalancheproof(
            42, 2000000000, bytes_to_wif(privkey.get_bytes()), stake)
        self.nodes[1].sendavalancheproof(proof)
        self.sync_proofs()

        time_now = int(time.time())
        peer_info = [x.getpeerinfo() for x in self.nodes]
        # Verify last_block, last_transaction and last_proof keys/values.
        for node, peer, field in product(
                range(self.num_nodes), range(2),
            ['last_block', 'last_transaction', 'last_proof']):
            assert field in peer_info[node][peer].keys()
            if peer_info[node][peer][field] != 0:
                assert_approx(peer_info[node][peer][field], time_now, vspan=60)
        # check both sides of bidirectional connection between nodes
        # the address bound to on one side will be the source address for the
        # other node
        assert_equal(peer_info[0][0]['addrbind'], peer_info[1][0]['addr'])
        assert_equal(peer_info[1][0]['addrbind'], peer_info[0][0]['addr'])
        assert_equal(peer_info[0][0]['minfeefilter'], Decimal("5.00"))
        assert_equal(peer_info[1][0]['minfeefilter'], Decimal("10.00"))
        # check the `servicesnames` field
        for info in peer_info:
            assert_net_servicesnames(int(info[0]["services"], 0x10),
                                     info[0]["servicesnames"])

        assert_equal(peer_info[0][0]['connection_type'], 'inbound')
        assert_equal(peer_info[0][1]['connection_type'], 'manual')

        assert_equal(peer_info[1][0]['connection_type'], 'manual')
        assert_equal(peer_info[1][1]['connection_type'], 'inbound')
    def run_test(self):
        """Main test logic"""
        assert_equal(self.nodes[0].getbalance(), 0)
        self.log.info("Improrting priv keys")
        self.nodes[0].importprivkey("cU1QaDgufU6FH24feZJ3f7RToVVbriuw7cZ91427mgbVA4Sk1kAi")
        self.nodes[0].importprivkey("cUNUxiqMtffurfGu9BKocHTvvnujynZh1Yrc4CVhgTBeQJfC9MqU")
        self.nodes[0].importprivkey("cTD9hmreLGnNPBPTz4TY4YbKCXZXfC6cyEXhcZTCzzycVmWwS643")
        expectedAmount = 30
        remaining = 1
        assert_equal(self.nodes[0].getbalance(), expectedAmount)

        node2addr = self.nodes[1].getnewaddress()
        self.log.info("attempt to spend coinbase in genesis block")
        amount = expectedAmount - remaining
        txid = self.nodes[0].sendtoaddress(node2addr, amount)

        self.log.info("node0 sent {} to node1 in tx={}".format(amount, txid))
        self.sync_mempools()

        confirmations = 10
        self.nodes[1].generate(nblocks=confirmations)
        self.sync_all()

        try:
            self.nodes[1].getrawtransaction(txid)
        except:
            raise Exception("node1 does not know about tx={}. it's a sign that coinbase tx can not be spent.".format(txid))

        assert_approx(float(self.nodes[0].getbalance()), remaining, vspan=0.001)

        balance = self.nodes[1].getbalance()
        txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), balance - remaining)
        self.nodes[1].generate(nblocks=confirmations)
        assert_approx(float(self.nodes[0].getbalance()), float((balance - remaining) + remaining), vspan=0.001)

        self.log.info("Trying to getrawtransaction on coinbase in genesis block")
        genesishash = self.nodes[0].getblockhash(0)
        genesis = self.nodes[0].getblock(genesishash)
        try:
            coinbase = self.nodes[0].getrawtransaction(genesis['tx'][0])
            self.log.info("Successfully fetched genesis coinbase tx with getrawtransaction")
        except Exception as e:
            self.log.error('Can not fetch genesis coinbase tx with getrawtransaction: {}'.format(e))
            raise
    def run_test(self):
        address_0 = self.nodes[0].getaccountaddress('')
        address_1 = self.nodes[1].getaccountaddress('')
        self.log.info('Address 0: ' + str(address_0))
        self.log.info('Address 1: ' + str(address_1))

        self.mine_blocks(0, 30)
        assert_equal(self.nodes[0].getblockcount(), 30)
        assert_equal(self.nodes[1].getblockcount(), 30)

        balance_0 = float(self.nodes[0].getbalance())
        balance_1 = float(self.nodes[1].getbalance())
        assert_approx(balance_0, 95.064278)  # 3.8025705377 * 5
        assert_equal(balance_1, Decimal('0.0'))

        self.log.info('Balances after initial mining')
        self.log.info('Balance node 0: ' + str(balance_0))
        self.log.info('Balance node 1: ' + str(balance_1))
        self.log_accounts("after 10")

        transaction_id = self.nodes[0].sendtoaddress(address_1, 2)
        tx_details = self.nodes[0].gettransaction(transaction_id)
        self.log.info(str(tx_details))
        assert_equal(tx_details['vout'][1]['value'], Decimal('2'))
        assert_equal(tx_details['vout'][1]['scriptPubKey']['addresses'][0],
                     address_1)
        assert_equal(tx_details['confirmations'], Decimal('0'))

        self.mine_blocks(0, 10)
        assert_equal(self.nodes[0].getblockcount(), 40)
        balance_0 = self.nodes[0].getbalance()
        balance_1 = self.nodes[1].getbalance()
        assert_equal(balance_1, Decimal('2'))
        node_0_accounts = self.nodes[0].listaccounts()
        node_1_accounts = self.nodes[1].listaccounts()
        assert_equal(node_0_accounts[''], balance_0)
        assert_equal(node_1_accounts[''], balance_1)

        tx_details = self.nodes[0].gettransaction(transaction_id)
        self.log.info(str(tx_details))
        assert_equal(tx_details['confirmations'], Decimal('10'))
예제 #10
0
def test_setfeerate(self, rbf_node, dest_address):
    self.log.info("Test setfeerate")

    def test_response(*, wallet="RBF wallet", requested=0, expected=0, error=None, msg):
        assert_equal(rbf_node.setfeerate(requested), {"wallet_name": wallet, "fee_rate": expected, ("error" if error else "result"): msg})

    # Test setfeerate with too high/low values returns expected errors
    new = Decimal("10000.001")
    test_response(requested=new, error=True, msg=f"The requested fee rate of {new} sat/vB cannot be greater than the wallet max fee rate of 10000.000 sat/vB. The current setting of 0 (unset) for this wallet remains unchanged.")
    new = Decimal("0.999")
    test_response(requested=new, error=True, msg=f"The requested fee rate of {new} sat/vB cannot be less than the minimum relay fee rate of 1.000 sat/vB. The current setting of 0 (unset) for this wallet remains unchanged.")
    fee_rate = Decimal("2.001")
    test_response(requested=fee_rate, expected=fee_rate, msg=f"Fee rate for transactions with this wallet successfully set to {fee_rate} sat/vB")
    new = Decimal("1.999")
    test_response(requested=new, expected=fee_rate, error=True, msg=f"The requested fee rate of {new} sat/vB cannot be less than the wallet min fee rate of 2.000 sat/vB. The current setting of {fee_rate} sat/vB for this wallet remains unchanged.")

    # Test setfeerate with valid values returns expected results
    rbfid = spend_one_input(rbf_node, dest_address)
    fee_rate = 25
    test_response(requested=fee_rate, expected=fee_rate, msg="Fee rate for transactions with this wallet successfully set to 25.000 sat/vB")
    bumped_tx = rbf_node.bumpfee(rbfid)
    bumped_txdetails = rbf_node.getrawtransaction(bumped_tx["txid"], True)
    allow_for_bytes_offset = len(bumped_txdetails['vout']) * 2  # potentially up to 2 bytes per output
    actual_fee = bumped_tx["fee"] * COIN
    assert_approx(actual_fee, fee_rate * bumped_txdetails['vsize'], fee_rate * allow_for_bytes_offset)
    test_response(msg="Fee rate for transactions with this wallet successfully unset. By default, automatic fee selection will be used.")

    # Test setfeerate with a different -maxtxfee
    self.restart_node(1, ["-maxtxfee=0.000025"] + self.extra_args[1])
    new = "2.501"
    test_response(requested=new, error=True, msg=f"The requested fee rate of {new} sat/vB cannot be greater than the wallet max fee rate of 2.500 sat/vB. The current setting of 0 (unset) for this wallet remains unchanged.")

    self.restart_node(1, self.extra_args[1])
    rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
    self.connect_nodes(1, 0)
    self.clear_mempool()
예제 #11
0
 def mine_blocks(self, nodeId, numberOfBlocks, blockvalue, moneysupplyAtEnd,
                 difficulty):
     timeBetweenBlocks = 120
     for _ in range(numberOfBlocks):
         self.log.info("Mining block " + str(self.blocks_mined + 1))
         self.setmocktimeforallnodes(self.mocktime)
         self.mocktime = self.mocktime + timeBetweenBlocks
         self.nodes[nodeId].generate(1)
         self.blocks_mined += 1
         info = self.nodes[nodeId].getinfo()
         self.log.info("moneysupply " + str(info['moneysupply']))
         mininginfo = self.nodes[nodeId].getmininginfo()
         assert_equal(
             mininginfo['blockvalue'],
             blockvalue)  # use blockvalue instead of powreward for checking
         assert_approx(mininginfo['difficulty']['proof-of-work'],
                       difficulty,
                       vspan=1E-12)
         self.log.info(
             str(self.blocks_mined) + " Difficulty " +
             str(mininginfo['difficulty']['proof-of-work']))
     info = self.nodes[nodeId].getinfo()
     assert_equal(int(info['moneysupply'] * 1000000), moneysupplyAtEnd)
     self.sync_all()
예제 #12
0
    def test_option_feerate(self):
        self.log.info(
            "Test fundrawtxn with explicit fee rates (fee_rate sat/vB and feeRate BTC/kvB)"
        )
        node = self.nodes[3]
        # 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 = {node.getnewaddress(): 1}
        rawtx = node.createrawtransaction(inputs, outputs)

        result = node.fundrawtransaction(
            rawtx)  # uses self.min_relay_tx_fee (set by settxfee)
        btc_kvb_to_sat_vb = 100000  # (1e5)
        result1 = node.fundrawtransaction(
            rawtx, {"fee_rate": 2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee})
        result2 = node.fundrawtransaction(
            rawtx, {"feeRate": 2 * self.min_relay_tx_fee})
        result3 = node.fundrawtransaction(
            rawtx,
            {"fee_rate": 10 * btc_kvb_to_sat_vb * self.min_relay_tx_fee})
        result4 = node.fundrawtransaction(
            rawtx, {"feeRate": 10 * self.min_relay_tx_fee})
        result_fee_rate = result['fee'] * 1000 / count_bytes(result['hex'])
        assert_fee_amount(result1['fee'], count_bytes(result2['hex']),
                          2 * result_fee_rate)
        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)
        assert_fee_amount(result4['fee'], count_bytes(result3['hex']),
                          10 * result_fee_rate)

        # With no arguments passed, expect fee of 141 satoshis.
        assert_approx(node.fundrawtransaction(rawtx)["fee"],
                      vexp=0.00000141,
                      vspan=0.00000001)
        # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
        result = node.fundrawtransaction(rawtx, {"fee_rate": 10000})
        assert_approx(result["fee"], vexp=0.0141, vspan=0.0001)

        self.log.info("Test fundrawtxn with invalid estimate_mode settings")
        for k, v in {"number": 42, "object": {"foo": "bar"}}.items():
            assert_raises_rpc_error(
                -3, "Expected type string for estimate_mode, got {}".format(k),
                node.fundrawtransaction, rawtx, {
                    "estimate_mode": v,
                    "conf_target": 0.1,
                    "add_inputs": True
                })
        for mode in ["", "foo", Decimal("3.141592")]:
            assert_raises_rpc_error(
                -8,
                'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"',
                node.fundrawtransaction, rawtx, {
                    "estimate_mode": mode,
                    "conf_target": 0.1,
                    "add_inputs": True
                })

        self.log.info("Test fundrawtxn with invalid conf_target settings")
        for mode in ["unset", "economical", "conservative"]:
            self.log.debug("{}".format(mode))
            for k, v in {"string": "", "object": {"foo": "bar"}}.items():
                assert_raises_rpc_error(
                    -3,
                    "Expected type number for conf_target, got {}".format(k),
                    node.fundrawtransaction, rawtx, {
                        "estimate_mode": mode,
                        "conf_target": v,
                        "add_inputs": True
                    })
            for n in [-1, 0, 1009]:
                assert_raises_rpc_error(
                    -8,
                    "Invalid conf_target, must be between 1 and 1008",  # max value of 1008 per src/policy/fees.h
                    node.fundrawtransaction,
                    rawtx,
                    {
                        "estimate_mode": mode,
                        "conf_target": n,
                        "add_inputs": True
                    })

        self.log.info("Test invalid fee rate settings")
        assert_raises_rpc_error(
            -8, "Invalid fee_rate 0.000 sat/vB (must be greater than 0)",
            node.fundrawtransaction, rawtx, {
                "fee_rate": 0,
                "add_inputs": True
            })
        assert_raises_rpc_error(
            -8,
            "Invalid feeRate 0.00000000 SUGAR/kvB (must be greater than 0)",
            node.fundrawtransaction, rawtx, {
                "feeRate": 0,
                "add_inputs": True
            })
        for param, value in {("fee_rate", 100000), ("feeRate", 1.000)}:
            assert_raises_rpc_error(
                -4,
                "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
                node.fundrawtransaction, rawtx, {
                    param: value,
                    "add_inputs": True
                })
            assert_raises_rpc_error(-3, "Amount out of range",
                                    node.fundrawtransaction, rawtx, {
                                        "fee_rate": -1,
                                        "add_inputs": True
                                    })
            assert_raises_rpc_error(-3, "Amount is not a number or string",
                                    node.fundrawtransaction, rawtx, {
                                        "fee_rate": {
                                            "foo": "bar"
                                        },
                                        "add_inputs": True
                                    })
            assert_raises_rpc_error(-3, "Invalid amount",
                                    node.fundrawtransaction, rawtx, {
                                        "fee_rate": "",
                                        "add_inputs": True
                                    })

        self.log.info(
            "Test min fee rate checks are bypassed with fundrawtxn, e.g. a fee_rate under 1 sat/vB is allowed"
        )
        node.fundrawtransaction(rawtx, {
            "fee_rate": 0.99999999,
            "add_inputs": True
        })
        node.fundrawtransaction(rawtx, {
            "feeRate": 0.00000999,
            "add_inputs": True
        })

        self.log.info(
            "- raises RPC error if both feeRate and fee_rate are passed")
        assert_raises_rpc_error(
            -8,
            "Cannot specify both fee_rate (sat/vB) and feeRate (SUGAR/kvB)",
            node.fundrawtransaction, rawtx, {
                "fee_rate": 0.1,
                "feeRate": 0.1,
                "add_inputs": True
            })

        self.log.info(
            "- raises RPC error if both feeRate and estimate_mode passed")
        assert_raises_rpc_error(
            -8, "Cannot specify both estimate_mode and feeRate",
            node.fundrawtransaction, rawtx, {
                "estimate_mode": "economical",
                "feeRate": 0.1,
                "add_inputs": True
            })

        for param in ["feeRate", "fee_rate"]:
            self.log.info(
                "- raises RPC error if both {} and conf_target are passed".
                format(param))
            assert_raises_rpc_error(
                -8,
                "Cannot specify both conf_target and {}. Please provide either a confirmation "
                "target in blocks for automatic fee estimation, or an explicit fee rate."
                .format(param), node.fundrawtransaction, rawtx, {
                    param: 1,
                    "conf_target": 1,
                    "add_inputs": True
                })

        self.log.info(
            "- raises RPC error if both fee_rate and estimate_mode are passed")
        assert_raises_rpc_error(
            -8, "Cannot specify both estimate_mode and fee_rate",
            node.fundrawtransaction, rawtx, {
                "fee_rate": 1,
                "estimate_mode": "economical",
                "add_inputs": True
            })
예제 #13
0
    def run_test(self):
        self.log.info("Setting up")
        # Mine some coins
        self.generate(self.nodes[0], COINBASE_MATURITY + 1)

        # Get some addresses from the two nodes
        addr1 = [self.nodes[1].getnewaddress() for _ in range(3)]
        addr2 = [self.nodes[2].getnewaddress() for _ in range(3)]
        addrs = addr1 + addr2

        # Send 1 + 0.5 coin to each address
        [self.nodes[0].sendtoaddress(addr, 1.0) for addr in addrs]
        [self.nodes[0].sendtoaddress(addr, 0.5) for addr in addrs]

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

        # For each node, send 0.2 coins back to 0;
        # - node[1] should pick one 0.5 UTXO and leave the rest
        # - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a
        #   given address, and leave the rest
        self.log.info(
            "Test sending transactions picks one UTXO group and leaves the rest"
        )
        txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx1 = self.nodes[1].getrawtransaction(txid1, True)
        # txid1 should have 1 input and 2 outputs
        assert_equal(1, len(tx1["vin"]))
        assert_equal(2, len(tx1["vout"]))
        # one output should be 0.2, the other should be ~0.3
        v = [vout["value"] for vout in tx1["vout"]]
        v.sort()
        assert_approx(v[0], vexp=0.2, vspan=0.0001)
        assert_approx(v[1], vexp=0.3, vspan=0.0001)

        txid2 = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx2 = self.nodes[2].getrawtransaction(txid2, True)
        # txid2 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx2["vin"]))
        assert_equal(2, len(tx2["vout"]))
        # one output should be 0.2, the other should be ~1.3
        v = [vout["value"] for vout in tx2["vout"]]
        v.sort()
        assert_approx(v[0], vexp=0.2, vspan=0.0001)
        assert_approx(v[1], vexp=1.3, vspan=0.0001)

        self.log.info(
            "Test avoiding partial spends if warranted, even if avoidpartialspends is disabled"
        )
        self.sync_all()
        self.generate(self.nodes[0], 1)
        # Nodes 1-2 now have confirmed UTXOs (letters denote destinations):
        # Node #1:      Node #2:
        # - A  1.0      - D0 1.0
        # - B0 1.0      - D1 0.5
        # - B1 0.5      - E0 1.0
        # - C0 1.0      - E1 0.5
        # - C1 0.5      - F  ~1.3
        # - D ~0.3
        assert_approx(self.nodes[1].getbalance(), vexp=4.3, vspan=0.0001)
        assert_approx(self.nodes[2].getbalance(), vexp=4.3, vspan=0.0001)
        # Sending 1.4 umk should pick one 1.0 + one more. For node #1,
        # this could be (A / B0 / C0) + (B1 / C1 / D). We ensure that it is
        # B0 + B1 or C0 + C1, because this avoids partial spends while not being
        # detrimental to transaction cost
        txid3 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.4)
        tx3 = self.nodes[1].getrawtransaction(txid3, True)
        # tx3 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx3["vin"]))
        assert_equal(2, len(tx3["vout"]))
        # the accumulated value should be 1.5, so the outputs should be
        # ~0.1 and 1.4 and should come from the same destination
        values = [vout["value"] for vout in tx3["vout"]]
        values.sort()
        assert_approx(values[0], vexp=0.1, vspan=0.0001)
        assert_approx(values[1], vexp=1.4, vspan=0.0001)

        input_txids = [vin["txid"] for vin in tx3["vin"]]
        input_addrs = [
            self.nodes[1].gettransaction(txid)['details'][0]['address']
            for txid in input_txids
        ]
        assert_equal(input_addrs[0], input_addrs[1])
        # Node 2 enforces avoidpartialspends so needs no checking here

        tx4_ungrouped_fee = 2820
        tx4_grouped_fee = 4160
        tx5_6_ungrouped_fee = 5520
        tx5_6_grouped_fee = 8240

        self.log.info("Test wallet option maxapsfee")
        addr_aps = self.nodes[3].getnewaddress()
        self.nodes[0].sendtoaddress(addr_aps, 1.0)
        self.nodes[0].sendtoaddress(addr_aps, 1.0)
        self.generate(self.nodes[0], 1)
        with self.nodes[3].assert_debug_log([
                f'Fee non-grouped = {tx4_ungrouped_fee}, grouped = {tx4_grouped_fee}, using grouped'
        ]):
            txid4 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(),
                                                0.1)
        tx4 = self.nodes[3].getrawtransaction(txid4, True)
        # tx4 should have 2 inputs and 2 outputs although one output would
        # have been enough and the transaction caused higher fees
        assert_equal(2, len(tx4["vin"]))
        assert_equal(2, len(tx4["vout"]))

        addr_aps2 = self.nodes[3].getnewaddress()
        [self.nodes[0].sendtoaddress(addr_aps2, 1.0) for _ in range(5)]
        self.generate(self.nodes[0], 1)
        with self.nodes[3].assert_debug_log([
                f'Fee non-grouped = {tx5_6_ungrouped_fee}, grouped = {tx5_6_grouped_fee}, using non-grouped'
        ]):
            txid5 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(),
                                                2.95)
        tx5 = self.nodes[3].getrawtransaction(txid5, True)
        # tx5 should have 3 inputs (1.0, 1.0, 1.0) and 2 outputs
        assert_equal(3, len(tx5["vin"]))
        assert_equal(2, len(tx5["vout"]))

        # Test wallet option maxapsfee with node 4, which sets maxapsfee
        # 1 sat higher, crossing the threshold from non-grouped to grouped.
        self.log.info(
            "Test wallet option maxapsfee threshold from non-grouped to grouped"
        )
        addr_aps3 = self.nodes[4].getnewaddress()
        [self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)]
        self.generate(self.nodes[0], 1)
        with self.nodes[4].assert_debug_log([
                f'Fee non-grouped = {tx5_6_ungrouped_fee}, grouped = {tx5_6_grouped_fee}, using grouped'
        ]):
            txid6 = self.nodes[4].sendtoaddress(self.nodes[0].getnewaddress(),
                                                2.95)
        tx6 = self.nodes[4].getrawtransaction(txid6, True)
        # tx6 should have 5 inputs and 2 outputs
        assert_equal(5, len(tx6["vin"]))
        assert_equal(2, len(tx6["vout"]))

        # Empty out node2's wallet
        self.nodes[2].sendtoaddress(address=self.nodes[0].getnewaddress(),
                                    amount=self.nodes[2].getbalance(),
                                    subtractfeefromamount=True)
        self.sync_all()
        self.generate(self.nodes[0], 1)

        self.log.info(
            "Fill a wallet with 10,000 outputs corresponding to the same scriptPubKey"
        )
        for _ in range(5):
            raw_tx = self.nodes[0].createrawtransaction([{
                "txid": "0" * 64,
                "vout": 0
            }], [{
                addr2[0]: 0.05
            }])
            tx = tx_from_hex(raw_tx)
            tx.vin = []
            tx.vout = [tx.vout[0]] * 2000
            funded_tx = self.nodes[0].fundrawtransaction(tx.serialize().hex())
            signed_tx = self.nodes[0].signrawtransactionwithwallet(
                funded_tx['hex'])
            self.nodes[0].sendrawtransaction(signed_tx['hex'])
            self.generate(self.nodes[0], 1)

        # Check that we can create a transaction that only requires ~100 of our
        # utxos, without pulling in all outputs and creating a transaction that
        # is way too big.
        self.log.info(
            "Test creating txn that only requires ~100 of our UTXOs without pulling in all outputs"
        )
        assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5)
예제 #14
0
    def run_test(self):
        # Mine some coins
        self.nodes[0].generate(110)

        # Get some addresses from the two nodes
        addr1 = [self.nodes[1].getnewaddress() for i in range(3)]
        addr2 = [self.nodes[2].getnewaddress() for i in range(3)]
        addrs = addr1 + addr2

        # Send 1 + 0.5 coin to each address
        [self.nodes[0].sendtoaddress(addr, 1.0) for addr in addrs]
        [self.nodes[0].sendtoaddress(addr, 0.5) for addr in addrs]

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

        # For each node, send 0.2 coins back to 0;
        # - node[1] should pick one 0.5 UTXO and leave the rest
        # - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a
        #   given address, and leave the rest
        txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx1 = self.nodes[1].getrawtransaction(txid1, True)
        # txid1 should have 1 input and 2 outputs
        assert_equal(1, len(tx1["vin"]))
        assert_equal(2, len(tx1["vout"]))
        # one output should be 0.2, the other should be ~0.3
        v = [vout["value"] for vout in tx1["vout"]]
        v.sort()
        assert_approx(v[0], 0.2)
        assert_approx(v[1], 0.3, 0.0001)

        txid2 = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx2 = self.nodes[2].getrawtransaction(txid2, True)
        # txid2 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx2["vin"]))
        assert_equal(2, len(tx2["vout"]))
        # one output should be 0.2, the other should be ~1.3
        v = [vout["value"] for vout in tx2["vout"]]
        v.sort()
        assert_approx(v[0], 0.2)
        assert_approx(v[1], 1.3, 0.0001)

        # Empty out node2's wallet
        self.nodes[2].sendtoaddress(address=self.nodes[0].getnewaddress(),
                                    amount=self.nodes[2].getbalance(),
                                    subtractfeefromamount=True)
        self.sync_all()
        self.nodes[0].generate(1)

        # Fill node2's wallet with 10000 outputs corresponding to the same
        # scriptPubKey
        for i in range(5):
            raw_tx = self.nodes[0].createrawtransaction([{
                "txid": "0" * 64,
                "vout": 0
            }], [{
                addr2[0]: 0.05
            }])
            tx = FromHex(CTransaction(), raw_tx)
            tx.vin = []
            tx.vout = [tx.vout[0]] * 2000
            funded_tx = self.nodes[0].fundrawtransaction(ToHex(tx))
            signed_tx = self.nodes[0].signrawtransactionwithwallet(
                funded_tx['hex'])
            self.nodes[0].sendrawtransaction(signed_tx['hex'])
            self.nodes[0].generate(1)

        self.sync_all()

        # Check that we can create a transaction that only requires ~100 of our
        # utxos, without pulling in all outputs and creating a transaction that
        # is way too big.
        assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5)
예제 #15
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({'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
        assert '!segwit' not in tmpl['rules']
        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].getaddressinfo(newaddress)["pubkey"])
            multiscript = CScript([
                OP_1,
                hex_str_to_bytes(self.pubkey[-1]), OP_1, OP_CHECKMULTISIG
            ])
            p2sh_ms_addr = self.nodes[i].addmultisigaddress(
                1, [self.pubkey[-1]], '', 'p2sh-segwit')['address']
            bip173_ms_addr = self.nodes[i].addmultisigaddress(
                1, [self.pubkey[-1]], '', 'bech32')['address']
            assert_equal(p2sh_ms_addr, script_to_p2sh_p2wsh(multiscript))
            assert_equal(bip173_ms_addr, script_to_p2wsh(multiscript))
            p2sh_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_spendable_utxo(self.nodes[0], 50),
                                        self.pubkey[n], False,
                                        Decimal("49.999")))
                    p2sh_ids[n][v].append(
                        send_to_witness(v, self.nodes[0],
                                        find_spendable_utxo(self.nodes[0], 50),
                                        self.pubkey[n], True,
                                        Decimal("49.999")))

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

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

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

        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

        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.nodes[2].generate(4)  # blocks 428-431

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

        self.log.info(
            "Verify default node can't accept txs with missing witness")
        # unsigned, no scriptsig
        self.fail_accept(self.nodes[0], "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]))

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

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

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

        self.log.info("Verify default node can now use witness txs")
        self.success_mine(self.nodes[0], wit_ids[NODE_0][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
        assert '!segwit' in tmpl['rules']

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

        tx1_hex = self.nodes[0].gettransaction(txid1)['hex']
        tx1 = FromHex(CTransaction(), tx1_hex)

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

        # Check that weight and vsize are properly reported in mempool entry (txid1)
        assert_equal(self.nodes[0].getmempoolentry(txid1)["vsize"],
                     (self.nodes[0].getmempoolentry(txid1)["weight"] + 3) // 4)
        assert_equal(
            self.nodes[0].getmempoolentry(txid1)["weight"],
            len(tx1.serialize_without_witness()) * 3 +
            len(tx1.serialize_with_witness()))

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

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

        # Check that weight and vsize are properly reported in mempool entry (txid2)
        assert_equal(self.nodes[0].getmempoolentry(txid2)["vsize"],
                     (self.nodes[0].getmempoolentry(txid2)["weight"] + 3) // 4)
        assert_equal(
            self.nodes[0].getmempoolentry(txid2)["weight"],
            len(tx.serialize_without_witness()) * 3 +
            len(tx.serialize_with_witness()))

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

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

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

        # Check that weight and vsize are properly reported in mempool entry (txid3)
        assert_equal(self.nodes[0].getmempoolentry(txid3)["vsize"],
                     (self.nodes[0].getmempoolentry(txid3)["weight"] + 3) // 4)
        assert_equal(
            self.nodes[0].getmempoolentry(txid3)["weight"],
            len(tx.serialize_without_witness()) * 3 +
            len(tx.serialize_with_witness()))

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

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

        self.log.info("Verify behaviour of importaddress and listunspent")

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

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

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

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

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

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

        multisig_without_privkey_address = self.nodes[0].addmultisigaddress(
            2, [pubkeys[3], pubkeys[4]])['address']
        script = 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].getaddressinfo(i)
            if (v['isscript']):
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                # p2sh multisig with compressed keys should always be spendable
                spendable_anytime.extend([p2sh])
                # bare multisig can be watched and signed, but is not treated as ours
                solvable_after_importaddress.extend([bare])
                # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after direct importaddress
                spendable_after_importaddress.extend([p2wsh, p2sh_p2wsh])
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # normal P2PKH and P2PK with compressed keys should always be spendable
                spendable_anytime.extend([p2pkh, p2pk])
                # P2SH_P2PK, P2SH_P2PKH with compressed keys are spendable after direct importaddress
                spendable_after_importaddress.extend([
                    p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh,
                    p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ])
                # P2WPKH and P2SH_P2WPKH with compressed keys should always be spendable
                spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])

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

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

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

        op1 = CScript([OP_1])
        op0 = CScript([OP_0])
        # 2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe is the P2SH(P2PKH) version of mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V
        unsolvable_address_key = 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].getaddressinfo(i)
            if (v['isscript']):
                bare = hex_str_to_bytes(v['hex'])
                importlist.append(bare.hex())
                importlist.append(CScript([OP_0, sha256(bare)]).hex())
            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(p2pk.hex())
                importlist.append(p2pkh.hex())
                importlist.append(CScript([OP_0, hash160(pubkey)]).hex())
                importlist.append(CScript([OP_0, sha256(p2pk)]).hex())
                importlist.append(CScript([OP_0, sha256(p2pkh)]).hex())

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

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

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

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

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

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

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

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

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

        premature_witaddress = []

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

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

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

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

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

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

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

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

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

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

            # Assert it is properly saved
            self.stop_node(1)
            self.start_node(1)
            assert_equal(self.nodes[1].gettransaction(txid, True)["txid"],
                         txid)
            assert_equal(
                self.nodes[1].listtransactions("*", 1, 0, True)[0]["txid"],
                txid)
예제 #16
0
    def run_test(self):
        # Create and fund a raw tx for sending 10 BTC
        psbtx1 = self.nodes[0].walletcreatefundedpsbt(
            [], {self.nodes[2].getnewaddress(): 10})['psbt']

        # If inputs are specified, do not automatically add more:
        utxo1 = self.nodes[0].listunspent()[0]
        assert_raises_rpc_error(-4, "Insufficient funds",
                                self.nodes[0].walletcreatefundedpsbt,
                                [{
                                    "txid": utxo1['txid'],
                                    "vout": utxo1['vout']
                                }], {self.nodes[2].getnewaddress(): 90})

        psbtx1 = self.nodes[0].walletcreatefundedpsbt(
            [{
                "txid": utxo1['txid'],
                "vout": utxo1['vout']
            }], {self.nodes[2].getnewaddress(): 90}, 0,
            {"add_inputs": True})['psbt']
        assert_equal(len(self.nodes[0].decodepsbt(psbtx1)['tx']['vin']), 2)

        # Inputs argument can be null
        self.nodes[0].walletcreatefundedpsbt(
            None, {self.nodes[2].getnewaddress(): 10})

        # Node 1 should not be able to add anything to it but still return the psbtx same as before
        psbtx = self.nodes[1].walletprocesspsbt(psbtx1)['psbt']
        assert_equal(psbtx1, psbtx)

        # Sign the transaction and send
        signed_tx = self.nodes[0].walletprocesspsbt(psbtx)['psbt']
        final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex']
        self.nodes[0].sendrawtransaction(final_tx)

        # Manually selected inputs can be locked:
        assert_equal(len(self.nodes[0].listlockunspent()), 0)
        utxo1 = self.nodes[0].listunspent()[0]
        psbtx1 = self.nodes[0].walletcreatefundedpsbt(
            [{
                "txid": utxo1['txid'],
                "vout": utxo1['vout']
            }], {self.nodes[2].getnewaddress(): 1}, 0,
            {"lockUnspents": True})["psbt"]
        assert_equal(len(self.nodes[0].listlockunspent()), 1)

        # Locks are ignored for manually selected inputs
        self.nodes[0].walletcreatefundedpsbt([{
            "txid": utxo1['txid'],
            "vout": utxo1['vout']
        }], {self.nodes[2].getnewaddress(): 1}, 0)

        # Create p2sh, p2wpkh, and p2wsh addresses
        pubkey0 = self.nodes[0].getaddressinfo(
            self.nodes[0].getnewaddress())['pubkey']
        pubkey1 = self.nodes[1].getaddressinfo(
            self.nodes[1].getnewaddress())['pubkey']
        pubkey2 = self.nodes[2].getaddressinfo(
            self.nodes[2].getnewaddress())['pubkey']

        # Setup watchonly wallets
        self.nodes[2].createwallet(wallet_name='wmulti',
                                   disable_private_keys=True)
        wmulti = self.nodes[2].get_wallet_rpc('wmulti')

        # Create all the addresses
        p2sh = wmulti.addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "",
                                         "legacy")['address']
        p2wsh = wmulti.addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "",
                                          "bech32")['address']
        p2sh_p2wsh = wmulti.addmultisigaddress(2, [pubkey0, pubkey1, pubkey2],
                                               "", "p2sh-segwit")['address']
        if not self.options.descriptors:
            wmulti.importaddress(p2sh)
            wmulti.importaddress(p2wsh)
            wmulti.importaddress(p2sh_p2wsh)
        p2wpkh = self.nodes[1].getnewaddress("", "bech32")
        p2pkh = self.nodes[1].getnewaddress("", "legacy")
        p2sh_p2wpkh = self.nodes[1].getnewaddress("", "p2sh-segwit")

        # fund those addresses
        rawtx = self.nodes[0].createrawtransaction(
            [], {
                p2sh: 10,
                p2wsh: 10,
                p2wpkh: 10,
                p2sh_p2wsh: 10,
                p2sh_p2wpkh: 10,
                p2pkh: 10
            })
        rawtx = self.nodes[0].fundrawtransaction(rawtx, {"changePosition": 3})
        signed_tx = self.nodes[0].signrawtransactionwithwallet(
            rawtx['hex'])['hex']
        txid = self.nodes[0].sendrawtransaction(signed_tx)
        self.nodes[0].generate(6)
        self.sync_all()

        # Find the output pos
        p2sh_pos = -1
        p2wsh_pos = -1
        p2wpkh_pos = -1
        p2pkh_pos = -1
        p2sh_p2wsh_pos = -1
        p2sh_p2wpkh_pos = -1
        decoded = self.nodes[0].decoderawtransaction(signed_tx)
        for out in decoded['vout']:
            if out['scriptPubKey']['address'] == p2sh:
                p2sh_pos = out['n']
            elif out['scriptPubKey']['address'] == p2wsh:
                p2wsh_pos = out['n']
            elif out['scriptPubKey']['address'] == p2wpkh:
                p2wpkh_pos = out['n']
            elif out['scriptPubKey']['address'] == p2sh_p2wsh:
                p2sh_p2wsh_pos = out['n']
            elif out['scriptPubKey']['address'] == p2sh_p2wpkh:
                p2sh_p2wpkh_pos = out['n']
            elif out['scriptPubKey']['address'] == p2pkh:
                p2pkh_pos = out['n']

        inputs = [{
            "txid": txid,
            "vout": p2wpkh_pos
        }, {
            "txid": txid,
            "vout": p2sh_p2wpkh_pos
        }, {
            "txid": txid,
            "vout": p2pkh_pos
        }]
        outputs = [{self.nodes[1].getnewaddress(): 29.99}]

        # spend single key from node 1
        created_psbt = self.nodes[1].walletcreatefundedpsbt(inputs, outputs)
        walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(
            created_psbt['psbt'])
        # Make sure it has both types of UTXOs
        decoded = self.nodes[1].decodepsbt(walletprocesspsbt_out['psbt'])
        assert 'non_witness_utxo' in decoded['inputs'][0]
        assert 'witness_utxo' in decoded['inputs'][0]
        # Check decodepsbt fee calculation (input values shall only be counted once per UTXO)
        assert_equal(decoded['fee'], created_psbt['fee'])
        assert_equal(walletprocesspsbt_out['complete'], True)
        self.nodes[1].sendrawtransaction(self.nodes[1].finalizepsbt(
            walletprocesspsbt_out['psbt'])['hex'])

        self.log.info(
            "Test walletcreatefundedpsbt fee rate of 10000 sat/vB and 0.1 BTC/kvB produces a total fee at or slightly below -maxtxfee (~0.05290000)"
        )
        res1 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {
            "fee_rate": 10000,
            "add_inputs": True
        })
        assert_approx(res1["fee"], 0.055, 0.005)
        res2 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {
            "feeRate": "0.1",
            "add_inputs": True
        })
        assert_approx(res2["fee"], 0.055, 0.005)

        self.log.info(
            "Test min fee rate checks with walletcreatefundedpsbt are bypassed, e.g. a fee_rate under 1 sat/vB is allowed"
        )
        res3 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {
            "fee_rate": "0.999",
            "add_inputs": True
        })
        assert_approx(res3["fee"], 0.00000381, 0.0000001)
        res4 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {
            "feeRate": 0.00000999,
            "add_inputs": True
        })
        assert_approx(res4["fee"], 0.00000381, 0.0000001)

        self.log.info(
            "Test min fee rate checks with walletcreatefundedpsbt are bypassed and that funding non-standard 'zero-fee' transactions is valid"
        )
        for param, zero_value in product(
            ["fee_rate", "feeRate"],
            [0, 0.000, 0.00000000, "0", "0.000", "0.00000000"]):
            assert_equal(
                0,
                self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {
                    param: zero_value,
                    "add_inputs": True
                })["fee"])

        self.log.info("Test invalid fee rate settings")
        for param, value in {("fee_rate", 100000), ("feeRate", 1)}:
            assert_raises_rpc_error(
                -4,
                "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
                self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {
                    param: value,
                    "add_inputs": True
                })
            assert_raises_rpc_error(-3, "Amount out of range",
                                    self.nodes[1].walletcreatefundedpsbt,
                                    inputs, outputs, 0, {
                                        param: -1,
                                        "add_inputs": True
                                    })
            assert_raises_rpc_error(-3, "Amount is not a number or string",
                                    self.nodes[1].walletcreatefundedpsbt,
                                    inputs, outputs, 0, {
                                        param: {
                                            "foo": "bar"
                                        },
                                        "add_inputs": True
                                    })
            # Test fee rate values that don't pass fixed-point parsing checks.
            for invalid_value in [
                    "", 0.000000001, 1e-09, 1.111111111, 1111111111111111,
                    "31.999999999999999999999"
            ]:
                assert_raises_rpc_error(-3, "Invalid amount",
                                        self.nodes[1].walletcreatefundedpsbt,
                                        inputs, outputs, 0, {
                                            param: invalid_value,
                                            "add_inputs": True
                                        })
        # Test fee_rate values that cannot be represented in sat/vB.
        for invalid_value in [
                0.0001, 0.00000001, 0.00099999, 31.99999999, "0.0001",
                "0.00000001", "0.00099999", "31.99999999"
        ]:
            assert_raises_rpc_error(-3, "Invalid amount",
                                    self.nodes[1].walletcreatefundedpsbt,
                                    inputs, outputs, 0, {
                                        "fee_rate": invalid_value,
                                        "add_inputs": True
                                    })

        self.log.info(
            "- raises RPC error if both feeRate and fee_rate are passed")
        assert_raises_rpc_error(
            -8, "Cannot specify both fee_rate (rie/vB) and feeRate (RIC/kvB)",
            self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {
                "fee_rate": 0.1,
                "feeRate": 0.1,
                "add_inputs": True
            })

        self.log.info(
            "- raises RPC error if both feeRate and estimate_mode passed")
        assert_raises_rpc_error(
            -8, "Cannot specify both estimate_mode and feeRate",
            self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {
                "estimate_mode": "economical",
                "feeRate": 0.1,
                "add_inputs": True
            })

        for param in ["feeRate", "fee_rate"]:
            self.log.info(
                "- raises RPC error if both {} and conf_target are passed".
                format(param))
            assert_raises_rpc_error(
                -8,
                "Cannot specify both conf_target and {}. Please provide either a confirmation "
                "target in blocks for automatic fee estimation, or an explicit fee rate."
                .format(param), self.nodes[1].walletcreatefundedpsbt, inputs,
                outputs, 0, {
                    param: 1,
                    "conf_target": 1,
                    "add_inputs": True
                })

        self.log.info(
            "- raises RPC error if both fee_rate and estimate_mode are passed")
        assert_raises_rpc_error(
            -8, "Cannot specify both estimate_mode and fee_rate",
            self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {
                "fee_rate": 1,
                "estimate_mode": "economical",
                "add_inputs": True
            })

        self.log.info("- raises RPC error with invalid estimate_mode settings")
        for k, v in {"number": 42, "object": {"foo": "bar"}}.items():
            assert_raises_rpc_error(
                -3, "Expected type string for estimate_mode, got {}".format(k),
                self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {
                    "estimate_mode": v,
                    "conf_target": 0.1,
                    "add_inputs": True
                })
        for mode in ["", "foo", Decimal("3.141592")]:
            assert_raises_rpc_error(
                -8,
                'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"',
                self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {
                    "estimate_mode": mode,
                    "conf_target": 0.1,
                    "add_inputs": True
                })

        self.log.info("- raises RPC error with invalid conf_target settings")
        for mode in ["unset", "economical", "conservative"]:
            self.log.debug("{}".format(mode))
            for k, v in {"string": "", "object": {"foo": "bar"}}.items():
                assert_raises_rpc_error(
                    -3,
                    "Expected type number for conf_target, got {}".format(k),
                    self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {
                        "estimate_mode": mode,
                        "conf_target": v,
                        "add_inputs": True
                    })
            for n in [-1, 0, 1009]:
                assert_raises_rpc_error(
                    -8,
                    "Invalid conf_target, must be between 1 and 1008",  # max value of 1008 per src/policy/fees.h
                    self.nodes[1].walletcreatefundedpsbt,
                    inputs,
                    outputs,
                    0,
                    {
                        "estimate_mode": mode,
                        "conf_target": n,
                        "add_inputs": True
                    })

        self.log.info(
            "Test walletcreatefundedpsbt with too-high fee rate produces total fee well above -maxtxfee and raises RPC error"
        )
        # previously this was silently capped at -maxtxfee
        for bool_add, outputs_array in {
                True: outputs,
                False: [{
                    self.nodes[1].getnewaddress(): 1
                }]
        }.items():
            msg = "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)"
            assert_raises_rpc_error(-4, msg,
                                    self.nodes[1].walletcreatefundedpsbt,
                                    inputs, outputs_array, 0, {
                                        "fee_rate": 1000000,
                                        "add_inputs": bool_add
                                    })
            assert_raises_rpc_error(-4, msg,
                                    self.nodes[1].walletcreatefundedpsbt,
                                    inputs, outputs_array, 0, {
                                        "feeRate": 1,
                                        "add_inputs": bool_add
                                    })

        self.log.info("Test various PSBT operations")
        # partially sign multisig things with node 1
        psbtx = wmulti.walletcreatefundedpsbt(
            inputs=[{
                "txid": txid,
                "vout": p2wsh_pos
            }, {
                "txid": txid,
                "vout": p2sh_pos
            }, {
                "txid": txid,
                "vout": p2sh_p2wsh_pos
            }],
            outputs={self.nodes[1].getnewaddress(): 29.99},
            options={'changeAddress':
                     self.nodes[1].getrawchangeaddress()})['psbt']
        walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx)
        psbtx = walletprocesspsbt_out['psbt']
        assert_equal(walletprocesspsbt_out['complete'], False)

        # Unload wmulti, we don't need it anymore
        wmulti.unloadwallet()

        # partially sign with node 2. This should be complete and sendable
        walletprocesspsbt_out = self.nodes[2].walletprocesspsbt(psbtx)
        assert_equal(walletprocesspsbt_out['complete'], True)
        self.nodes[2].sendrawtransaction(self.nodes[2].finalizepsbt(
            walletprocesspsbt_out['psbt'])['hex'])

        # check that walletprocesspsbt fails to decode a non-psbt
        rawtx = self.nodes[1].createrawtransaction(
            [{
                "txid": txid,
                "vout": p2wpkh_pos
            }], {self.nodes[1].getnewaddress(): 9.99})
        assert_raises_rpc_error(-22, "TX decode failed",
                                self.nodes[1].walletprocesspsbt, rawtx)

        # Convert a non-psbt to psbt and make sure we can decode it
        rawtx = self.nodes[0].createrawtransaction(
            [], {self.nodes[1].getnewaddress(): 10})
        rawtx = self.nodes[0].fundrawtransaction(rawtx)
        new_psbt = self.nodes[0].converttopsbt(rawtx['hex'])
        self.nodes[0].decodepsbt(new_psbt)

        # Make sure that a non-psbt with signatures cannot be converted
        # Error could be either "TX decode failed" (segwit inputs causes parsing to fail) or "Inputs must not have scriptSigs and scriptWitnesses"
        # We must set iswitness=True because the serialized transaction has inputs and is therefore a witness transaction
        signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx['hex'])
        assert_raises_rpc_error(-22,
                                "",
                                self.nodes[0].converttopsbt,
                                hexstring=signedtx['hex'],
                                iswitness=True)
        assert_raises_rpc_error(-22,
                                "",
                                self.nodes[0].converttopsbt,
                                hexstring=signedtx['hex'],
                                permitsigdata=False,
                                iswitness=True)
        # Unless we allow it to convert and strip signatures
        self.nodes[0].converttopsbt(signedtx['hex'], True)

        # Explicitly allow converting non-empty txs
        new_psbt = self.nodes[0].converttopsbt(rawtx['hex'])
        self.nodes[0].decodepsbt(new_psbt)

        # Create outputs to nodes 1 and 2
        node1_addr = self.nodes[1].getnewaddress()
        node2_addr = self.nodes[2].getnewaddress()
        txid1 = self.nodes[0].sendtoaddress(node1_addr, 13)
        txid2 = self.nodes[0].sendtoaddress(node2_addr, 13)
        blockhash = self.nodes[0].generate(6)[0]
        self.sync_all()
        vout1 = find_output(self.nodes[1], txid1, 13, blockhash=blockhash)
        vout2 = find_output(self.nodes[2], txid2, 13, blockhash=blockhash)

        # Create a psbt spending outputs from nodes 1 and 2
        psbt_orig = self.nodes[0].createpsbt(
            [{
                "txid": txid1,
                "vout": vout1
            }, {
                "txid": txid2,
                "vout": vout2
            }], {self.nodes[0].getnewaddress(): 25.999})

        # Update psbts, should only have data for one input and not the other
        psbt1 = self.nodes[1].walletprocesspsbt(psbt_orig, False,
                                                "ALL")['psbt']
        psbt1_decoded = self.nodes[0].decodepsbt(psbt1)
        assert psbt1_decoded['inputs'][0] and not psbt1_decoded['inputs'][1]
        # Check that BIP32 path was added
        assert "bip32_derivs" in psbt1_decoded['inputs'][0]
        psbt2 = self.nodes[2].walletprocesspsbt(psbt_orig, False, "ALL",
                                                False)['psbt']
        psbt2_decoded = self.nodes[0].decodepsbt(psbt2)
        assert not psbt2_decoded['inputs'][0] and psbt2_decoded['inputs'][1]
        # Check that BIP32 paths were not added
        assert "bip32_derivs" not in psbt2_decoded['inputs'][1]

        # Sign PSBTs (workaround issue #18039)
        psbt1 = self.nodes[1].walletprocesspsbt(psbt_orig)['psbt']
        psbt2 = self.nodes[2].walletprocesspsbt(psbt_orig)['psbt']

        # Combine, finalize, and send the psbts
        combined = self.nodes[0].combinepsbt([psbt1, psbt2])
        finalized = self.nodes[0].finalizepsbt(combined)['hex']
        self.nodes[0].sendrawtransaction(finalized)
        self.nodes[0].generate(6)
        self.sync_all()

        # Test additional args in walletcreatepsbt
        # Make sure both pre-included and funded inputs
        # have the correct sequence numbers based on
        # replaceable arg
        block_height = self.nodes[0].getblockcount()
        unspent = self.nodes[0].listunspent()[0]
        psbtx_info = self.nodes[0].walletcreatefundedpsbt(
            [{
                "txid": unspent["txid"],
                "vout": unspent["vout"]
            }], [{
                self.nodes[2].getnewaddress(): unspent["amount"] + 1
            }], block_height + 2, {
                "replaceable": False,
                "add_inputs": True
            }, False)
        decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
        for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"],
                                  decoded_psbt["inputs"]):
            assert_greater_than(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
            assert "bip32_derivs" not in psbt_in
        assert_equal(decoded_psbt["tx"]["locktime"], block_height + 2)

        # Same construction with only locktime set and RBF explicitly enabled
        psbtx_info = self.nodes[0].walletcreatefundedpsbt(
            [{
                "txid": unspent["txid"],
                "vout": unspent["vout"]
            }], [{
                self.nodes[2].getnewaddress(): unspent["amount"] + 1
            }], block_height, {
                "replaceable": True,
                "add_inputs": True
            }, True)
        decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
        for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"],
                                  decoded_psbt["inputs"]):
            assert_equal(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
            assert "bip32_derivs" in psbt_in
        assert_equal(decoded_psbt["tx"]["locktime"], block_height)

        # Same construction without optional arguments
        psbtx_info = self.nodes[0].walletcreatefundedpsbt(
            [], [{
                self.nodes[2].getnewaddress(): unspent["amount"] + 1
            }])
        decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
        for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"],
                                  decoded_psbt["inputs"]):
            assert_equal(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
            assert "bip32_derivs" in psbt_in
        assert_equal(decoded_psbt["tx"]["locktime"], 0)

        # Same construction without optional arguments, for a node with -walletrbf=0
        unspent1 = self.nodes[1].listunspent()[0]
        psbtx_info = self.nodes[1].walletcreatefundedpsbt(
            [{
                "txid": unspent1["txid"],
                "vout": unspent1["vout"]
            }], [{
                self.nodes[2].getnewaddress(): unspent1["amount"] + 1
            }], block_height, {"add_inputs": True})
        decoded_psbt = self.nodes[1].decodepsbt(psbtx_info["psbt"])
        for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"],
                                  decoded_psbt["inputs"]):
            assert_greater_than(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
            assert "bip32_derivs" in psbt_in

        # Make sure change address wallet does not have P2SH innerscript access to results in success
        # when attempting BnB coin selection
        self.nodes[0].walletcreatefundedpsbt(
            [], [{
                self.nodes[2].getnewaddress(): unspent["amount"] + 1
            }], block_height + 2,
            {"changeAddress": self.nodes[1].getnewaddress()}, False)

        # Make sure the wallet's change type is respected by default
        small_output = {self.nodes[0].getnewaddress(): 0.1}
        psbtx_native = self.nodes[0].walletcreatefundedpsbt([], [small_output])
        self.assert_change_type(psbtx_native, "witness_v0_keyhash")
        psbtx_legacy = self.nodes[1].walletcreatefundedpsbt([], [small_output])
        self.assert_change_type(psbtx_legacy, "pubkeyhash")

        # Make sure the change type of the wallet can also be overwritten
        psbtx_np2wkh = self.nodes[1].walletcreatefundedpsbt(
            [], [small_output], 0, {"change_type": "p2sh-segwit"})
        self.assert_change_type(psbtx_np2wkh, "scripthash")

        # Make sure the change type cannot be specified if a change address is given
        invalid_options = {
            "change_type": "legacy",
            "changeAddress": self.nodes[0].getnewaddress()
        }
        assert_raises_rpc_error(
            -8, "both change address and address type options",
            self.nodes[0].walletcreatefundedpsbt, [], [small_output], 0,
            invalid_options)

        # Regression test for 14473 (mishandling of already-signed witness transaction):
        psbtx_info = self.nodes[0].walletcreatefundedpsbt(
            [{
                "txid": unspent["txid"],
                "vout": unspent["vout"]
            }], [{
                self.nodes[2].getnewaddress(): unspent["amount"] + 1
            }], 0, {"add_inputs": True})
        complete_psbt = self.nodes[0].walletprocesspsbt(psbtx_info["psbt"])
        double_processed_psbt = self.nodes[0].walletprocesspsbt(
            complete_psbt["psbt"])
        assert_equal(complete_psbt, double_processed_psbt)
        # We don't care about the decode result, but decoding must succeed.
        self.nodes[0].decodepsbt(double_processed_psbt["psbt"])

        # Make sure unsafe inputs are included if specified
        self.nodes[2].createwallet(wallet_name="unsafe")
        wunsafe = self.nodes[2].get_wallet_rpc("unsafe")
        self.nodes[0].sendtoaddress(wunsafe.getnewaddress(), 2)
        self.sync_mempools()
        assert_raises_rpc_error(-4, "Insufficient funds",
                                wunsafe.walletcreatefundedpsbt, [],
                                [{
                                    self.nodes[0].getnewaddress(): 1
                                }])
        wunsafe.walletcreatefundedpsbt([], [{
            self.nodes[0].getnewaddress(): 1
        }], 0, {"include_unsafe": True})

        # BIP 174 Test Vectors

        # Check that unknown values are just passed through
        unknown_psbt = "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAA="
        unknown_out = self.nodes[0].walletprocesspsbt(unknown_psbt)['psbt']
        assert_equal(unknown_psbt, unknown_out)

        # Open the data file
        with open(os.path.join(os.path.dirname(os.path.realpath(__file__)),
                               'data/rpc_psbt.json'),
                  encoding='utf-8') as f:
            d = json.load(f)
            invalids = d['invalid']
            valids = d['valid']
            creators = d['creator']
            signers = d['signer']
            combiners = d['combiner']
            finalizers = d['finalizer']
            extractors = d['extractor']

        # Invalid PSBTs
        for invalid in invalids:
            assert_raises_rpc_error(-22, "TX decode failed",
                                    self.nodes[0].decodepsbt, invalid)

        # Valid PSBTs
        for valid in valids:
            self.nodes[0].decodepsbt(valid)

        # Creator Tests
        for creator in creators:
            created_tx = self.nodes[0].createpsbt(creator['inputs'],
                                                  creator['outputs'])
            assert_equal(created_tx, creator['result'])

        # Signer tests
        for i, signer in enumerate(signers):
            self.nodes[2].createwallet(wallet_name="wallet{}".format(i))
            wrpc = self.nodes[2].get_wallet_rpc("wallet{}".format(i))
            for key in signer['privkeys']:
                wrpc.importprivkey(key)
            signed_tx = wrpc.walletprocesspsbt(signer['psbt'])['psbt']
            assert_equal(signed_tx, signer['result'])

        # Combiner test
        for combiner in combiners:
            combined = self.nodes[2].combinepsbt(combiner['combine'])
            assert_equal(combined, combiner['result'])

        # Empty combiner test
        assert_raises_rpc_error(-8, "Parameter 'txs' cannot be empty",
                                self.nodes[0].combinepsbt, [])

        # Finalizer test
        for finalizer in finalizers:
            finalized = self.nodes[2].finalizepsbt(finalizer['finalize'],
                                                   False)['psbt']
            assert_equal(finalized, finalizer['result'])

        # Extractor test
        for extractor in extractors:
            extracted = self.nodes[2].finalizepsbt(extractor['extract'],
                                                   True)['hex']
            assert_equal(extracted, extractor['result'])

        # Unload extra wallets
        for i, signer in enumerate(signers):
            self.nodes[2].unloadwallet("wallet{}".format(i))

        # TODO: Re-enable this for segwit v1
        # self.test_utxo_conversion()

        # Test that psbts with p2pkh outputs are created properly
        p2pkh = self.nodes[0].getnewaddress(address_type='legacy')
        psbt = self.nodes[1].walletcreatefundedpsbt([], [{
            p2pkh: 1
        }], 0, {"includeWatching": True}, True)
        self.nodes[0].decodepsbt(psbt['psbt'])

        # Test decoding error: invalid base64
        assert_raises_rpc_error(-22, "TX decode failed invalid base64",
                                self.nodes[0].decodepsbt,
                                ";definitely not base64;")

        # Send to all types of addresses
        addr1 = self.nodes[1].getnewaddress("", "bech32")
        txid1 = self.nodes[0].sendtoaddress(addr1, 11)
        vout1 = find_output(self.nodes[0], txid1, 11)
        addr2 = self.nodes[1].getnewaddress("", "legacy")
        txid2 = self.nodes[0].sendtoaddress(addr2, 11)
        vout2 = find_output(self.nodes[0], txid2, 11)
        addr3 = self.nodes[1].getnewaddress("", "p2sh-segwit")
        txid3 = self.nodes[0].sendtoaddress(addr3, 11)
        vout3 = find_output(self.nodes[0], txid3, 11)
        self.sync_all()

        def test_psbt_input_keys(psbt_input, keys):
            """Check that the psbt input has only the expected keys."""
            assert_equal(set(keys), set(psbt_input.keys()))

        # Create a PSBT. None of the inputs are filled initially
        psbt = self.nodes[1].createpsbt([{
            "txid": txid1,
            "vout": vout1
        }, {
            "txid": txid2,
            "vout": vout2
        }, {
            "txid": txid3,
            "vout": vout3
        }], {self.nodes[0].getnewaddress(): 32.999})
        decoded = self.nodes[1].decodepsbt(psbt)
        test_psbt_input_keys(decoded['inputs'][0], [])
        test_psbt_input_keys(decoded['inputs'][1], [])
        test_psbt_input_keys(decoded['inputs'][2], [])

        # Update a PSBT with UTXOs from the node
        # Bech32 inputs should be filled with witness UTXO. Other inputs should not be filled because they are non-witness
        updated = self.nodes[1].utxoupdatepsbt(psbt)
        decoded = self.nodes[1].decodepsbt(updated)
        test_psbt_input_keys(decoded['inputs'][0], ['witness_utxo'])
        test_psbt_input_keys(decoded['inputs'][1], [])
        test_psbt_input_keys(decoded['inputs'][2], [])

        # Try again, now while providing descriptors, making P2SH-segwit work, and causing bip32_derivs and redeem_script to be filled in
        descs = [
            self.nodes[1].getaddressinfo(addr)['desc']
            for addr in [addr1, addr2, addr3]
        ]
        updated = self.nodes[1].utxoupdatepsbt(psbt=psbt, descriptors=descs)
        decoded = self.nodes[1].decodepsbt(updated)
        test_psbt_input_keys(decoded['inputs'][0],
                             ['witness_utxo', 'bip32_derivs'])
        test_psbt_input_keys(decoded['inputs'][1], [])
        test_psbt_input_keys(decoded['inputs'][2],
                             ['witness_utxo', 'bip32_derivs', 'redeem_script'])

        # Two PSBTs with a common input should not be joinable
        psbt1 = self.nodes[1].createpsbt(
            [{
                "txid": txid1,
                "vout": vout1
            }], {self.nodes[0].getnewaddress(): Decimal('10.999')})
        assert_raises_rpc_error(-8, "exists in multiple PSBTs",
                                self.nodes[1].joinpsbts, [psbt1, updated])

        # Join two distinct PSBTs
        addr4 = self.nodes[1].getnewaddress("", "p2sh-segwit")
        txid4 = self.nodes[0].sendtoaddress(addr4, 5)
        vout4 = find_output(self.nodes[0], txid4, 5)
        self.nodes[0].generate(6)
        self.sync_all()
        psbt2 = self.nodes[1].createpsbt(
            [{
                "txid": txid4,
                "vout": vout4
            }], {self.nodes[0].getnewaddress(): Decimal('4.999')})
        psbt2 = self.nodes[1].walletprocesspsbt(psbt2)['psbt']
        psbt2_decoded = self.nodes[0].decodepsbt(psbt2)
        assert "final_scriptwitness" in psbt2_decoded['inputs'][
            0] and "final_scriptSig" in psbt2_decoded['inputs'][0]
        joined = self.nodes[0].joinpsbts([psbt, psbt2])
        joined_decoded = self.nodes[0].decodepsbt(joined)
        assert len(joined_decoded['inputs']) == 4 and len(
            joined_decoded['outputs']
        ) == 2 and "final_scriptwitness" not in joined_decoded['inputs'][
            3] and "final_scriptSig" not in joined_decoded['inputs'][3]

        # Check that joining shuffles the inputs and outputs
        # 10 attempts should be enough to get a shuffled join
        shuffled = False
        for _ in range(10):
            shuffled_joined = self.nodes[0].joinpsbts([psbt, psbt2])
            shuffled |= joined != shuffled_joined
            if shuffled:
                break
        assert shuffled

        # Newly created PSBT needs UTXOs and updating
        addr = self.nodes[1].getnewaddress("", "p2sh-segwit")
        txid = self.nodes[0].sendtoaddress(addr, 7)
        addrinfo = self.nodes[1].getaddressinfo(addr)
        blockhash = self.nodes[0].generate(6)[0]
        self.sync_all()
        vout = find_output(self.nodes[0], txid, 7, blockhash=blockhash)
        psbt = self.nodes[1].createpsbt(
            [{
                "txid": txid,
                "vout": vout
            }],
            {self.nodes[0].getnewaddress("", "p2sh-segwit"): Decimal('6.999')})
        analyzed = self.nodes[0].analyzepsbt(psbt)
        assert not analyzed['inputs'][0]['has_utxo'] and not analyzed[
            'inputs'][0]['is_final'] and analyzed['inputs'][0][
                'next'] == 'updater' and analyzed['next'] == 'updater'

        # After update with wallet, only needs signing
        updated = self.nodes[1].walletprocesspsbt(psbt, False, 'ALL',
                                                  True)['psbt']
        analyzed = self.nodes[0].analyzepsbt(updated)
        assert analyzed['inputs'][0][
            'has_utxo'] and not analyzed['inputs'][0]['is_final'] and analyzed[
                'inputs'][0]['next'] == 'signer' and analyzed[
                    'next'] == 'signer' and analyzed['inputs'][0]['missing'][
                        'signatures'][0] == addrinfo['embedded'][
                            'witness_program']

        # Check fee and size things
        assert analyzed['fee'] == Decimal(
            '0.001') and analyzed['estimated_vsize'] == 134 and analyzed[
                'estimated_feerate'] == Decimal('0.00746268')

        # After signing and finalizing, needs extracting
        signed = self.nodes[1].walletprocesspsbt(updated)['psbt']
        analyzed = self.nodes[0].analyzepsbt(signed)
        assert analyzed['inputs'][0]['has_utxo'] and analyzed['inputs'][0][
            'is_final'] and analyzed['next'] == 'extractor'

        self.log.info(
            "PSBT spending unspendable outputs should have error message and Creator as next"
        )
        analysis = self.nodes[0].analyzepsbt(
            'cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWAEHYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFv8/wADXYP/7//////8JxOh0LR2HAI8AAAAAAAEBIADC6wsAAAAAF2oUt/X69ELjeX2nTof+fZ10l+OyAokDAQcJAwEHEAABAACAAAEBIADC6wsAAAAAF2oUt/X69ELjeX2nTof+fZ10l+OyAokDAQcJAwEHENkMak8AAAAA'
        )
        assert_equal(analysis['next'], 'creator')
        assert_equal(analysis['error'],
                     'PSBT is not valid. Input 0 spends unspendable output')

        self.log.info(
            "PSBT with invalid values should have error message and Creator as next"
        )
        analysis = self.nodes[0].analyzepsbt(
            'cHNidP8BAHECAAAAAfA00BFgAm6tp86RowwH6BMImQNL5zXUcTT97XoLGz0BAAAAAAD/////AgD5ApUAAAAAFgAUKNw0x8HRctAgmvoevm4u1SbN7XL87QKVAAAAABYAFPck4gF7iL4NL4wtfRAKgQbghiTUAAAAAAABAR8AgIFq49AeABYAFJUDtxf2PHo641HEOBOAIvFMNTr2AAAA'
        )
        assert_equal(analysis['next'], 'creator')
        assert_equal(analysis['error'],
                     'PSBT is not valid. Input 0 has invalid value')

        self.log.info(
            "PSBT with signed, but not finalized, inputs should have Finalizer as next"
        )
        analysis = self.nodes[0].analyzepsbt(
            'cHNidP8BAHECAAAAAZYezcxdnbXoQCmrD79t/LzDgtUo9ERqixk8wgioAobrAAAAAAD9////AlDDAAAAAAAAFgAUy/UxxZuzZswcmFnN/E9DGSiHLUsuGPUFAAAAABYAFLsH5o0R38wXx+X2cCosTMCZnQ4baAAAAAABAR8A4fUFAAAAABYAFOBI2h5thf3+Lflb2LGCsVSZwsltIgIC/i4dtVARCRWtROG0HHoGcaVklzJUcwo5homgGkSNAnJHMEQCIGx7zKcMIGr7cEES9BR4Kdt/pzPTK3fKWcGyCJXb7MVnAiALOBgqlMH4GbC1HDh/HmylmO54fyEy4lKde7/BT/PWxwEBAwQBAAAAIgYC/i4dtVARCRWtROG0HHoGcaVklzJUcwo5homgGkSNAnIYDwVpQ1QAAIABAACAAAAAgAAAAAAAAAAAAAAiAgL+CIiB59NSCssOJRGiMYQK1chahgAaaJpIXE41Cyir+xgPBWlDVAAAgAEAAIAAAACAAQAAAAAAAAAA'
        )
        assert_equal(analysis['next'], 'finalizer')

        analysis = self.nodes[0].analyzepsbt(
            'cHNidP8BAHECAAAAAfA00BFgAm6tp86RowwH6BMImQNL5zXUcTT97XoLGz0BAAAAAAD/////AgCAgWrj0AcAFgAUKNw0x8HRctAgmvoevm4u1SbN7XL87QKVAAAXABYAFPck4gF7iL4NL4wtfRAKgQbghiTUAAAAAAABAR8A8gUqAQAAABYAFJUDtxf2PHo641HEOBOAIvFMNTr2AAAA'
        )
        assert_equal(analysis['next'], 'creator')
        assert_equal(analysis['error'],
                     'PSBT is not valid. Output amount invalid')

        analysis = self.nodes[0].analyzepsbt(
            'cHNidP8BAJoCAAAAAkvEW8NnDtdNtDpsmze+Ht2LH35IJcKv00jKAlUs21RrAwAAAAD/////S8Rbw2cO1020OmybN74e3Ysffkglwq/TSMoCVSzbVGsBAAAAAP7///8CwLYClQAAAAAWABSNJKzjaUb3uOxixsvh1GGE3fW7zQD5ApUAAAAAFgAUKNw0x8HRctAgmvoevm4u1SbN7XIAAAAAAAEAnQIAAAACczMa321tVHuN4GKWKRncycI22aX3uXgwSFUKM2orjRsBAAAAAP7///9zMxrfbW1Ue43gYpYpGdzJwjbZpfe5eDBIVQozaiuNGwAAAAAA/v///wIA+QKVAAAAABl2qRT9zXUVA8Ls5iVqynLHe5/vSe1XyYisQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAAAAAQEfQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAA=='
        )
        assert_equal(analysis['next'], 'creator')
        assert_equal(analysis['error'],
                     'PSBT is not valid. Input 0 specifies invalid prevout')

        assert_raises_rpc_error(
            -25, 'Inputs missing or spent', self.nodes[0].walletprocesspsbt,
            'cHNidP8BAJoCAAAAAkvEW8NnDtdNtDpsmze+Ht2LH35IJcKv00jKAlUs21RrAwAAAAD/////S8Rbw2cO1020OmybN74e3Ysffkglwq/TSMoCVSzbVGsBAAAAAP7///8CwLYClQAAAAAWABSNJKzjaUb3uOxixsvh1GGE3fW7zQD5ApUAAAAAFgAUKNw0x8HRctAgmvoevm4u1SbN7XIAAAAAAAEAnQIAAAACczMa321tVHuN4GKWKRncycI22aX3uXgwSFUKM2orjRsBAAAAAP7///9zMxrfbW1Ue43gYpYpGdzJwjbZpfe5eDBIVQozaiuNGwAAAAAA/v///wIA+QKVAAAAABl2qRT9zXUVA8Ls5iVqynLHe5/vSe1XyYisQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAAAAAQEfQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAA=='
        )
예제 #17
0
    def run_test(self):
        # Mine some coins
        self.nodes[0].generate(110)

        # Get some addresses from the two nodes
        addr1 = [self.nodes[1].getnewaddress() for _ in range(3)]
        addr2 = [self.nodes[2].getnewaddress() for _ in range(3)]
        addrs = addr1 + addr2

        # Send 1 + 0.5 coin to each address
        [self.nodes[0].sendtoaddress(addr, 1.0) for addr in addrs]
        [self.nodes[0].sendtoaddress(addr, 0.5) for addr in addrs]

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

        # For each node, send 0.2 coins back to 0;
        # - node[1] should pick one 0.5 UTXO and leave the rest
        # - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a
        #   given address, and leave the rest
        txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx1 = self.nodes[1].getrawtransaction(txid1, True)
        # txid1 should have 1 input and 2 outputs
        assert_equal(1, len(tx1["vin"]))
        assert_equal(2 + 1, len(tx1["vout"]))
        # one output should be 0.2, the other should be ~0.3
        v = [
            vout["value"] for vout in tx1["vout"]
            if vout["scriptPubKey"]["type"] != "fee"
        ]
        v.sort()
        assert_approx(v[0], vexp=0.2, vspan=0.0001)
        assert_approx(v[1], vexp=0.3, vspan=0.0001)

        txid2 = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx2 = self.nodes[2].getrawtransaction(txid2, True)
        # txid2 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx2["vin"]))
        assert_equal(2 + 1, len(tx2["vout"]))
        # one output should be 0.2, the other should be ~1.3
        v = [
            vout["value"] for vout in tx2["vout"]
            if vout["scriptPubKey"]["type"] != "fee"
        ]
        v.sort()
        assert_approx(v[0], vexp=0.2, vspan=0.0001)
        assert_approx(v[1], vexp=1.3, vspan=0.0001)

        # Test 'avoid partial if warranted, even if disabled'
        self.sync_all()
        self.nodes[0].generate(1)
        # Nodes 1-2 now have confirmed UTXOs (letters denote destinations):
        # Node #1:      Node #2:
        # - A  1.0      - D0 1.0
        # - B0 1.0      - D1 0.5
        # - B1 0.5      - E0 1.0
        # - C0 1.0      - E1 0.5
        # - C1 0.5      - F  ~1.3
        # - D ~0.3
        assert_approx(self.nodes[1].getbalance()['bitcoin'],
                      vexp=4.3,
                      vspan=0.0001)
        assert_approx(self.nodes[2].getbalance()['bitcoin'],
                      vexp=4.3,
                      vspan=0.0001)
        # Sending 1.4 btc should pick one 1.0 + one more. For node #1,
        # this could be (A / B0 / C0) + (B1 / C1 / D). We ensure that it is
        # B0 + B1 or C0 + C1, because this avoids partial spends while not being
        # detrimental to transaction cost
        txid3 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.4)
        tx3 = self.nodes[1].getrawtransaction(txid3, True)
        # tx3 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx3["vin"]))
        assert_equal(3, len(tx3["vout"]))  ## ELEMENTS: 2 outputs plus fee
        # the accumulated value should be 1.5, so the outputs should be
        # ~0.1 and 1.4 and should come from the same destination
        values = [vout["value"] for vout in tx3["vout"]]
        values.sort()
        assert_approx(values[0], vexp=0.00006, vspan=0.00001)
        assert_approx(values[1], vexp=0.1, vspan=0.0001)
        assert_approx(values[2], vexp=1.4, vspan=0.0001)

        input_txids = [vin["txid"] for vin in tx3["vin"]]
        input_addrs = [
            self.nodes[1].gettransaction(txid)['details'][0]['address']
            for txid in input_txids
        ]
        assert_equal(input_addrs[0], input_addrs[1])
        # Node 2 enforces avoidpartialspends so needs no checking here

        # Test wallet option maxapsfee with Node 3
        addr_aps = self.nodes[3].getnewaddress()
        self.nodes[0].sendtoaddress(addr_aps, 1.0)
        self.nodes[0].sendtoaddress(addr_aps, 1.0)
        self.nodes[0].generate(1)
        self.sync_all()
        with self.nodes[3].assert_debug_log(
            ['Fee non-grouped = 5140, grouped = 6520, using grouped']):
            txid4 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(),
                                                0.1)
        tx4 = self.nodes[3].getrawtransaction(txid4, True)
        # tx4 should have 2 inputs and 2 outputs although one output would
        # have been enough and the transaction caused higher fees
        assert_equal(2, len(tx4["vin"]))
        assert_equal(3, len(tx4["vout"]))  # ELEMENTS: plus fee

        addr_aps2 = self.nodes[3].getnewaddress()
        [self.nodes[0].sendtoaddress(addr_aps2, 1.0) for _ in range(5)]
        self.nodes[0].generate(1)
        self.sync_all()
        with self.nodes[3].assert_debug_log(
            ['Fee non-grouped = 7880, grouped = 10620, using non-grouped']):
            txid5 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(),
                                                2.95)
        tx5 = self.nodes[3].getrawtransaction(txid5, True)
        # tx5 should have 3 inputs (1.0, 1.0, 1.0) and 2 outputs
        assert_equal(3, len(tx5["vin"]))
        assert_equal(3, len(tx5["vout"]))  # ELEMENTS: plus fee

        # Test wallet option maxapsfee with node 4, which sets maxapsfee
        # 1 sat higher, crossing the threshold from non-grouped to grouped.
        addr_aps3 = self.nodes[4].getnewaddress()
        [self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)]
        self.nodes[0].generate(1)
        self.sync_all()
        with self.nodes[4].assert_debug_log(
            ['Fee non-grouped = 7880, grouped = 10620, using grouped']):
            txid6 = self.nodes[4].sendtoaddress(self.nodes[0].getnewaddress(),
                                                2.95)
        tx6 = self.nodes[4].getrawtransaction(txid6, True)
        # tx6 should have 5 inputs and 2 outputs
        assert_equal(5, len(tx6["vin"]))
        assert_equal(3, len(tx6["vout"]))  # ELEMENTS: plus fee

        # Empty out node2's wallet
        self.nodes[2].sendtoaddress(
            address=self.nodes[0].getnewaddress(),
            amount=self.nodes[2].getbalance()['bitcoin'],
            subtractfeefromamount=True)
        self.sync_all()
        self.nodes[0].generate(1)

        # Fill node2's wallet with 10000 outputs corresponding to the same
        # scriptPubKey
        for _ in range(5):
            raw_tx = self.nodes[0].createrawtransaction([{
                "txid": "0" * 64,
                "vout": 0
            }], [{
                addr2[0]: 0.10
            }])
            tx = FromHex(CTransaction(), raw_tx)
            tx.vin = []
            # ELEMENTS: lower number because outputs are bigger (otherwise tx gets too large)
            tx.vout = [tx.vout[0]] * 1000
            funded_tx = self.nodes[0].fundrawtransaction(ToHex(tx))
            signed_tx = self.nodes[0].signrawtransactionwithwallet(
                funded_tx['hex'])
            self.nodes[0].sendrawtransaction(signed_tx['hex'])
            self.nodes[0].generate(1)

        self.sync_all()

        # Check that we can create a transaction that only requires ~100 of our
        # utxos, without pulling in all outputs and creating a transaction that
        # is way too big.
        assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5)
예제 #18
0
    def run_test(self):
        # mine a few blocks and check that the balance is available after block 6
        self.mine_blocks(0, 20)
        mining_info = self.nodes[0].getmininginfo()
        
        for i in range(5):
            self.log.info(">>> MINING block "+str(i+21))
            self.mine_blocks(0,1)
            mining_info = self.nodes[0].getmininginfo()
            balance = self.nodes[0].getbalance()
            assert_equal(mining_info['blocks'], (20+i+1))
            assert_equal(mining_info['currentblocksize'], 1000)
            assert_equal(mining_info['N'], 32)
            # the low difficulty is only valid because of the low difficulty flag
            assert_equal(mining_info['difficulty']['proof-of-work'], Decimal('0.0000000777459625'))
            # low nfactor is set for testing
            assert_equal(mining_info['Nfactor'], 4)
            # powreward is based on 100,000,000 initial money supply for testing
            assert_approx(mining_info['powreward'], 3.80257)
            assert_approx(balance,60.841127 + i*3.80257)
        
        # mine block 6
        self.mine_blocks(0, 1)
        mining_info = self.nodes[0].getmininginfo()
        balance=self.nodes[0].getbalance()
        assert_equal(mining_info['blocks'], 26)
        assert_approx(balance,79.853986)

        # mine till block 9 (epoch)
        for i in range(3):
            self.mine_blocks(0, 1)
            mining_info = self.nodes[0].getmininginfo()
            assert_equal(mining_info['difficulty']['proof-of-work'], Decimal('0.0000000777459625'))
        assert_equal(mining_info['blocks'], 29)
        assert_approx(mining_info['powreward'], 3.8025705377)

        # mine block 10 (epoch calculation) and difficulty change
        self.mine_blocks(0, 1)
        mining_info = self.nodes[0].getmininginfo()
        balance=self.nodes[0].getbalance()
        assert_equal(mining_info['blocks'], 30)
        assert_equal(mining_info['difficulty']['proof-of-work'], Decimal('0.0000000777459625'))
        assert_approx(mining_info['powreward'], 3.8025705377)
        assert_approx(float(balance), 95.064278)

        # mine block 15 (pow reward available)
        self.mine_blocks(0, 5)
        mining_info = self.nodes[0].getmininginfo()
        balance=self.nodes[0].getbalance()
        assert_equal(mining_info['blocks'], 35)
        assert_equal(mining_info['difficulty']['proof-of-work'], Decimal('0.0000000777459625'))
        assert_approx(balance, 114.077144)
예제 #19
0
    def run_test(self):
        node = self.nodes[0]

        self.generate(node, 1, sync_fun=self.no_op) # Leave IBD

        node.createwallet(wallet_name='w0')
        node.createwallet(wallet_name='w1')
        node.createwallet(wallet_name='w2', disable_private_keys=True)
        w0 = node.get_wallet_rpc('w0')
        w1 = node.get_wallet_rpc('w1')
        w2 = node.get_wallet_rpc('w2')

        self.generatetoaddress(node, COINBASE_MATURITY + 1, w0.getnewaddress())
        assert_equal(w0.getbalance(), 50.0)
        assert_equal(w1.getbalance(), 0.0)

        address1 = w1.getnewaddress()
        address2 = w1.getnewaddress()

        # Add address1 as watch-only to w2
        w2.importpubkey(pubkey=w1.getaddressinfo(address1)["pubkey"])

        tx1 = node.createrawtransaction([], [{address1: 5.0}])
        tx2 = node.createrawtransaction([], [{address2: 10.0}])

        # w0 should be unaffected, w2 should see +5 for tx1
        assert_equal(w0.simulaterawtransaction([tx1])["balance_change"], 0.0)
        assert_equal(w2.simulaterawtransaction([tx1])["balance_change"], 5.0)

        # w1 should see +5 balance for tx1
        assert_equal(w1.simulaterawtransaction([tx1])["balance_change"], 5.0)

        # w0 should be unaffected, w2 should see +5 for both transactions
        assert_equal(w0.simulaterawtransaction([tx1, tx2])["balance_change"], 0.0)
        assert_equal(w2.simulaterawtransaction([tx1, tx2])["balance_change"], 5.0)

        # w1 should see +15 balance for both transactions
        assert_equal(w1.simulaterawtransaction([tx1, tx2])["balance_change"], 15.0)

        # w0 funds transaction; it should now see a decrease in (tx fee and payment), and w1 should see the same as above
        funding = w0.fundrawtransaction(tx1)
        tx1 = funding["hex"]
        tx1changepos = funding["changepos"]
        bitcoin_fee = Decimal(funding["fee"])

        # w0 sees fee + 5 btc decrease, w2 sees + 5 btc
        assert_approx(w0.simulaterawtransaction([tx1])["balance_change"], -(Decimal("5") + bitcoin_fee))
        assert_approx(w2.simulaterawtransaction([tx1])["balance_change"], Decimal("5"))

        # w1 sees same as before
        assert_equal(w1.simulaterawtransaction([tx1])["balance_change"], 5.0)

        # same inputs (tx) more than once should error
        assert_raises_rpc_error(-8, "Transaction(s) are spending the same output more than once", w0.simulaterawtransaction, [tx1,tx1])

        tx1ob = node.decoderawtransaction(tx1)
        tx1hex = tx1ob["txid"]
        tx1vout = 1 - tx1changepos
        # tx3 spends new w1 UTXO paying to w0
        tx3 = node.createrawtransaction([{"txid": tx1hex, "vout": tx1vout}], {w0.getnewaddress(): 4.9999})
        # tx4 spends new w1 UTXO paying to w1
        tx4 = node.createrawtransaction([{"txid": tx1hex, "vout": tx1vout}], {w1.getnewaddress(): 4.9999})

        # on their own, both should fail due to missing input(s)
        assert_raises_rpc_error(-8, "One or more transaction inputs have been spent already", w0.simulaterawtransaction, [tx3])
        assert_raises_rpc_error(-8, "One or more transaction inputs have been spent already", w1.simulaterawtransaction, [tx3])
        assert_raises_rpc_error(-8, "One or more transaction inputs have been spent already", w0.simulaterawtransaction, [tx4])
        assert_raises_rpc_error(-8, "One or more transaction inputs have been spent already", w1.simulaterawtransaction, [tx4])

        # they should succeed when including tx1:
        #       wallet                  tx3                             tx4
        #       w0                      -5 - bitcoin_fee + 4.9999       -5 - bitcoin_fee
        #       w1                      0                               +4.9999
        assert_approx(w0.simulaterawtransaction([tx1, tx3])["balance_change"], -Decimal("5") - bitcoin_fee + Decimal("4.9999"))
        assert_approx(w1.simulaterawtransaction([tx1, tx3])["balance_change"], 0)
        assert_approx(w0.simulaterawtransaction([tx1, tx4])["balance_change"], -Decimal("5") - bitcoin_fee)
        assert_approx(w1.simulaterawtransaction([tx1, tx4])["balance_change"], Decimal("4.9999"))

        # they should fail if attempting to include both tx3 and tx4
        assert_raises_rpc_error(-8, "Transaction(s) are spending the same output more than once", w0.simulaterawtransaction, [tx1, tx3, tx4])
        assert_raises_rpc_error(-8, "Transaction(s) are spending the same output more than once", w1.simulaterawtransaction, [tx1, tx3, tx4])

        # send tx1 to avoid reusing same UTXO below
        node.sendrawtransaction(w0.signrawtransactionwithwallet(tx1)["hex"])
        self.generate(node, 1, sync_fun=self.no_op) # Confirm tx to trigger error below
        self.sync_all()

        # w0 funds transaction 2; it should now see a decrease in (tx fee and payment), and w1 should see the same as above
        funding = w0.fundrawtransaction(tx2)
        tx2 = funding["hex"]
        bitcoin_fee2 = Decimal(funding["fee"])
        assert_approx(w0.simulaterawtransaction([tx2])["balance_change"], -(Decimal("10") + bitcoin_fee2))
        assert_approx(w1.simulaterawtransaction([tx2])["balance_change"], +(Decimal("10")))
        assert_approx(w2.simulaterawtransaction([tx2])["balance_change"], 0)

        # w0-w2 error due to tx1 already being mined
        assert_raises_rpc_error(-8, "One or more transaction inputs have been spent already", w0.simulaterawtransaction, [tx1, tx2])
        assert_raises_rpc_error(-8, "One or more transaction inputs have been spent already", w1.simulaterawtransaction, [tx1, tx2])
        assert_raises_rpc_error(-8, "One or more transaction inputs have been spent already", w2.simulaterawtransaction, [tx1, tx2])
예제 #20
0
    def test_sending_from_reused_address_fails(self):
        '''
        Test the simple case where [1] generates a new address A, then
        [0] sends 10 BCH to A.
        [1] spends 5 BCH from A. (leaving roughly 5 BCH useable)
        [0] sends 10 BCH to A again.
        [1] tries to spend 10 BCH (fails; dirty).
        [1] tries to spend 4 BCH (succeeds; change address sufficient)
        '''
        self.log.info("Test sending from reused address fails")

        fundaddr = self.nodes[1].getnewaddress(label="", address_type="legacy")
        retaddr = self.nodes[0].getnewaddress()

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 10 BCH output
        assert_unspent(
            self.nodes[1],
            total_count=1,
            total_sum=10,
            reused_supported=True,
            reused_count=0)
        # getbalances should show no used, 10 BCH trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})

        self.nodes[1].sendtoaddress(retaddr, 5)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 5 BCH output
        assert_unspent(
            self.nodes[1],
            total_count=1,
            total_sum=5,
            reused_supported=True,
            reused_count=0)
        # getbalances should show no used, 5 BCH trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})

        # For the second send, we transmute it to a related single-key address
        # to make sure it's also detected as re-use
        # NB: this is not very useful for ABC, but we keep the new variable
        # name for consistency.
        new_fundaddr = fundaddr

        self.nodes[0].sendtoaddress(new_fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 2 total outputs (5, 10 BCH), one unused (5),
        # one reused (10)
        assert_unspent(
            self.nodes[1],
            total_count=2,
            total_sum=15,
            reused_count=1,
            reused_sum=10)
        # getbalances should show 10 used, 5 BCH trusted
        assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5})

        # node 1 should now have a balance of 5 (no dirty) or 15 (including
        # dirty)
        assert_approx(self.nodes[1].getbalance(), 5, 0.001)
        assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 15, 0.001)

        assert_raises_rpc_error(-6, "Insufficient funds",
                                self.nodes[1].sendtoaddress, retaddr, 10)

        self.nodes[1].sendtoaddress(retaddr, 4)

        # listunspent should show 2 total outputs (1, 10 BCH), one unused (1),
        # one reused (10)
        assert_unspent(
            self.nodes[1],
            total_count=2,
            total_sum=11,
            reused_count=1,
            reused_sum=10)
        # getbalances should show 10 used, 1 BCH trusted
        assert_balances(self.nodes[1], mine={"used": 10, "trusted": 1})

        # node 1 should now have about 1 BCH left (no dirty) and 11 (including
        # dirty)
        assert_approx(self.nodes[1].getbalance(), 1, 0.001)
        assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 11, 0.001)
예제 #21
0
    def test_fund_send_fund_senddirty(self):
        '''
        Test the same as test_fund_send_fund_send, except send the 10 AUR with
        the avoid_reuse flag set to false. This means the 10 AUR send should succeed,
        where it fails in test_fund_send_fund_send.
        '''

        fundaddr = self.nodes[1].getnewaddress()
        retaddr = self.nodes[0].getnewaddress()

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 10 aur output
        assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0)
        # getbalances should show no used, 10 aur trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})
        # node 0 should not show a used entry, as it does not enable avoid_reuse
        assert("used" not in self.nodes[0].getbalances()["mine"])

        self.nodes[1].sendtoaddress(retaddr, 5)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 5 aur output
        assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0)
        # getbalances should show no used, 5 aur trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 2 total outputs (5, 10 aur), one unused (5), one reused (10)
        assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
        # getbalances should show 10 used, 5 aur trusted
        assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5}

        self.nodes[1].sendtoaddress(address=retaddr, amount=10, avoid_reuse=False)

        # listunspent should show 1 total outputs (5 aur), unused
        assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_count=0)
        # getbalances should show no used, 5 aur trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})

        # node 1 should now have about 5 aur left (for both cases)
        assert_approx(self.nodes[1].getbalance(), 5, 0.001)
        assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 5, 0.001)

    def test_fund_send_fund_send(self, second_addr_type):
        '''
        Test the simple case where [1] generates a new address A, then
        [0] sends 10 AUR to A.
        [1] spends 5 AUR from A. (leaving roughly 5 BTC useable)
        [0] sends 10 AUR to A again.
        [1] tries to spend 10 AUR (fails; dirty).
        [1] tries to spend 4 AUR (succeeds; change address sufficient)
        '''

        fundaddr = self.nodes[1].getnewaddress(label="", address_type="legacy")
        retaddr = self.nodes[0].getnewaddress()

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 10 aur output
        assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0)
        # getbalances should show no used, 10 aur trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})

        self.nodes[1].sendtoaddress(retaddr, 5)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 5 aur output
        assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0)
        # getbalances should show no used, 5 aur trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})

        # For the second send, we transmute it to a related single-key address
        # to make sure it's also detected as re-use
        fund_spk = self.nodes[0].getaddressinfo(fundaddr)["scriptPubKey"]
        fund_decoded = self.nodes[0].decodescript(fund_spk)
        if second_addr_type == "p2sh-segwit":
            new_fundaddr = fund_decoded["segwit"]["p2sh-segwit"]
        elif second_addr_type == "bech32":
            new_fundaddr = fund_decoded["segwit"]["addresses"][0]
        else:
            new_fundaddr = fundaddr
            assert_equal(second_addr_type, "legacy")

        self.nodes[0].sendtoaddress(new_fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 2 total outputs (5, 10 aur), one unused (5), one reused (10)
        assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
        # getbalances should show 10 used, 5 aur trusted
        assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5})

        # node 1 should now have a balance of 5 (no dirty) or 15 (including dirty)
        assert_approx(self.nodes[1].getbalance(), 5, 0.001)
        assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 15, 0.001)

        assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[1].sendtoaddress, retaddr, 10)

        self.nodes[1].sendtoaddress(retaddr, 4)

        # listunspent should show 2 total outputs (1, 10 aur), one unused (1), one reused (10)
        assert_unspent(self.nodes[1], total_count=2, total_sum=11, reused_count=1, reused_sum=10)
        # getbalances should show 10 used, 1 aur trusted
        assert_balances(self.nodes[1], mine={"used": 10, "trusted": 1})

        # node 1 should now have about 1 aur left (no dirty) and 11 (including dirty)
        assert_approx(self.nodes[1].getbalance(), 1, 0.001)
        assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 11, 0.001)

    def test_getbalances_used(self):
        '''
        getbalances and listunspent should pick up on reused addresses
        immediately, even for address reusing outputs created before the first
        transaction was spending from that address
        '''
        self.log.info("Test getbalances used category")

        # node under test should be completely empty
        assert_equal(self.nodes[1].getbalance(avoid_reuse=False), 0)

        new_addr = self.nodes[1].getnewaddress()
        ret_addr = self.nodes[0].getnewaddress()

        # send multiple transactions, reusing one address
        for _ in range(11):
            self.nodes[0].sendtoaddress(new_addr, 1)

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

        # send transaction that should not use all the available outputs
        # per the current coin selection algorithm
        self.nodes[1].sendtoaddress(ret_addr, 5)

        # getbalances and listunspent should show the remaining outputs
        # in the reused address as used/reused
        assert_unspent(self.nodes[1], total_count=2, total_sum=6, reused_count=1, reused_sum=1)
        assert_balances(self.nodes[1], mine={"used": 1, "trusted": 5})

if __name__ == '__main__':
    AvoidReuseTest().main()
예제 #22
0
    def run_test(self):
        # Create and fund a raw tx for sending 10 BTC
        psbtx1 = self.nodes[0].walletcreatefundedpsbt(
            [], {self.nodes[2].getnewaddress(): 10})['psbt']

        # If inputs are specified, do not automatically add more:
        utxo1 = self.nodes[0].listunspent()[0]
        assert_raises_rpc_error(-4, "Insufficient funds",
                                self.nodes[0].walletcreatefundedpsbt,
                                [{
                                    "txid": utxo1['txid'],
                                    "vout": utxo1['vout']
                                }], {self.nodes[2].getnewaddress(): 90})

        psbtx1 = self.nodes[0].walletcreatefundedpsbt(
            [{
                "txid": utxo1['txid'],
                "vout": utxo1['vout']
            }], {self.nodes[2].getnewaddress(): 90}, 0,
            {"add_inputs": True})['psbt']
        assert_equal(len(self.nodes[0].decodepsbt(psbtx1)['tx']['vin']), 2)

        # Node 1 should not be able to add anything to it but still return the
        # psbtx same as before
        psbtx = self.nodes[1].walletprocesspsbt(psbtx1)['psbt']
        assert_equal(psbtx1, psbtx)

        # Sign the transaction and send
        signed_tx = self.nodes[0].walletprocesspsbt(psbtx)['psbt']
        final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex']
        self.nodes[0].sendrawtransaction(final_tx)

        # Create p2sh, p2pkh addresses
        pubkey0 = self.nodes[0].getaddressinfo(
            self.nodes[0].getnewaddress())['pubkey']
        pubkey1 = self.nodes[1].getaddressinfo(
            self.nodes[1].getnewaddress())['pubkey']
        pubkey2 = self.nodes[2].getaddressinfo(
            self.nodes[2].getnewaddress())['pubkey']
        p2sh = self.nodes[1].addmultisigaddress(2, [pubkey0, pubkey1, pubkey2],
                                                "")['address']
        p2pkh = self.nodes[1].getnewaddress("")

        # fund those addresses
        rawtx = self.nodes[0].createrawtransaction([], {p2sh: 10, p2pkh: 10})
        rawtx = self.nodes[0].fundrawtransaction(rawtx, {"changePosition": 0})
        signed_tx = self.nodes[0].signrawtransactionwithwallet(
            rawtx['hex'])['hex']
        txid = self.nodes[0].sendrawtransaction(signed_tx)
        self.nodes[0].generate(6)
        self.sync_all()

        # Find the output pos
        p2sh_pos = -1
        p2pkh_pos = -1
        decoded = self.nodes[0].decoderawtransaction(signed_tx)
        for out in decoded['vout']:
            if out['scriptPubKey']['addresses'][0] == p2sh:
                p2sh_pos = out['n']
            elif out['scriptPubKey']['addresses'][0] == p2pkh:
                p2pkh_pos = out['n']

        # spend single key from node 1
        rawtx = self.nodes[1].walletcreatefundedpsbt(
            [{
                "txid": txid,
                "vout": p2pkh_pos
            }], {self.nodes[1].getnewaddress(): 9.99})['psbt']
        walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(rawtx)
        assert_equal(walletprocesspsbt_out['complete'], True)
        self.nodes[1].sendrawtransaction(self.nodes[1].finalizepsbt(
            walletprocesspsbt_out['psbt'])['hex'])

        # feeRate of 0.1 BCH / KB produces a total fee slightly below -maxtxfee
        res = self.nodes[1].walletcreatefundedpsbt(
            [{
                "txid": txid,
                "vout": p2sh_pos
            }, {
                "txid": txid,
                "vout": p2pkh_pos
            }], {self.nodes[1].getnewaddress(): 29.99}, 0, {
                     "feeRate": 0.1,
                     "add_inputs": True
                 })
        assert_approx(res["fee"], 0.065, 0.005)

        # feeRate of 10 BCH / KB produces a total fee well above -maxtxfee
        # previously this was silently capped at -maxtxfee
        assert_raises_rpc_error(-4,
                                "Fee exceeds maximum configured by -maxtxfee",
                                self.nodes[1].walletcreatefundedpsbt,
                                [{
                                    "txid": txid,
                                    "vout": p2sh_pos
                                }, {
                                    "txid": txid,
                                    "vout": p2pkh_pos
                                }], {self.nodes[1].getnewaddress(): 29.99}, 0,
                                {
                                    "feeRate": 10,
                                    "add_inputs": True
                                })
        assert_raises_rpc_error(-4,
                                "Fee exceeds maximum configured by -maxtxfee",
                                self.nodes[1].walletcreatefundedpsbt,
                                [{
                                    "txid": txid,
                                    "vout": p2sh_pos
                                }, {
                                    "txid": txid,
                                    "vout": p2pkh_pos
                                }], {self.nodes[1].getnewaddress(): 1}, 0, {
                                         "feeRate": 10,
                                         "add_inputs": False
                                     })

        # partially sign multisig things with node 1
        psbtx = self.nodes[1].walletcreatefundedpsbt(
            [{
                "txid": txid,
                "vout": p2sh_pos
            }], {self.nodes[1].getnewaddress(): 9.99})['psbt']
        walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx)
        psbtx = walletprocesspsbt_out['psbt']
        assert_equal(walletprocesspsbt_out['complete'], False)

        # partially sign with node 2. This should be complete and sendable
        walletprocesspsbt_out = self.nodes[2].walletprocesspsbt(psbtx)
        assert_equal(walletprocesspsbt_out['complete'], True)
        self.nodes[2].sendrawtransaction(self.nodes[2].finalizepsbt(
            walletprocesspsbt_out['psbt'])['hex'])

        # check that walletprocesspsbt fails to decode a non-psbt
        rawtx = self.nodes[1].createrawtransaction(
            [{
                "txid": txid,
                "vout": p2pkh_pos
            }], {self.nodes[1].getnewaddress(): 9.99})
        assert_raises_rpc_error(-22, "TX decode failed",
                                self.nodes[1].walletprocesspsbt, rawtx)

        # Convert a non-psbt to psbt and make sure we can decode it
        rawtx = self.nodes[0].createrawtransaction(
            [], {self.nodes[1].getnewaddress(): 10})
        rawtx = self.nodes[0].fundrawtransaction(rawtx)
        new_psbt = self.nodes[0].converttopsbt(rawtx['hex'])
        self.nodes[0].decodepsbt(new_psbt)

        # Make sure that a non-psbt with signatures cannot be converted
        # Error is "Inputs must not have scriptSigs"
        signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx['hex'])
        assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt,
                                signedtx['hex'])
        assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt,
                                signedtx['hex'], False)
        # Unless we allow it to convert and strip signatures
        self.nodes[0].converttopsbt(signedtx['hex'], True)

        # Explicilty allow converting non-empty txs
        new_psbt = self.nodes[0].converttopsbt(rawtx['hex'])
        self.nodes[0].decodepsbt(new_psbt)

        # Create outputs to nodes 1 and 2
        node1_addr = self.nodes[1].getnewaddress()
        node2_addr = self.nodes[2].getnewaddress()
        txid1 = self.nodes[0].sendtoaddress(node1_addr, 13)
        txid2 = self.nodes[0].sendtoaddress(node2_addr, 13)
        blockhash = self.nodes[0].generate(6)[0]
        self.sync_all()
        vout1 = find_output(self.nodes[1], txid1, 13, blockhash=blockhash)
        vout2 = find_output(self.nodes[2], txid2, 13, blockhash=blockhash)

        # Create a psbt spending outputs from nodes 1 and 2
        psbt_orig = self.nodes[0].createpsbt(
            [{
                "txid": txid1,
                "vout": vout1
            }, {
                "txid": txid2,
                "vout": vout2
            }], {self.nodes[0].getnewaddress(): 25.999})

        # Update psbts, should only have data for one input and not the other
        psbt1 = self.nodes[1].walletprocesspsbt(psbt_orig, False,
                                                "ALL|FORKID")['psbt']
        psbt1_decoded = self.nodes[0].decodepsbt(psbt1)
        assert psbt1_decoded['inputs'][0] and not psbt1_decoded['inputs'][1]
        # Check that BIP32 path was added
        assert "bip32_derivs" in psbt1_decoded['inputs'][0]
        psbt2 = self.nodes[2].walletprocesspsbt(psbt_orig, False, "ALL|FORKID",
                                                False)['psbt']
        psbt2_decoded = self.nodes[0].decodepsbt(psbt2)
        assert not psbt2_decoded['inputs'][0] and psbt2_decoded['inputs'][1]
        # Check that BIP32 paths were not added
        assert "bip32_derivs" not in psbt2_decoded['inputs'][1]

        # Sign PSBTs (workaround issue #18039)
        psbt1 = self.nodes[1].walletprocesspsbt(psbt_orig)['psbt']
        psbt2 = self.nodes[2].walletprocesspsbt(psbt_orig)['psbt']

        # Combine, finalize, and send the psbts
        combined = self.nodes[0].combinepsbt([psbt1, psbt2])
        finalized = self.nodes[0].finalizepsbt(combined)['hex']
        self.nodes[0].sendrawtransaction(finalized)
        self.nodes[0].generate(6)
        self.sync_all()

        block_height = self.nodes[0].getblockcount()
        unspent = self.nodes[0].listunspent()[0]

        # Make sure change address wallet does not have P2SH innerscript access to results in success
        # when attempting BnB coin selection
        self.nodes[0].walletcreatefundedpsbt(
            [], [{
                self.nodes[2].getnewaddress(): unspent["amount"] + 1
            }], block_height + 2,
            {"changeAddress": self.nodes[1].getnewaddress()}, False)

        # Regression test for 14473 (mishandling of already-signed
        # transaction):
        psbtx_info = self.nodes[0].walletcreatefundedpsbt(
            [{
                "txid": unspent["txid"],
                "vout": unspent["vout"]
            }], [{
                self.nodes[2].getnewaddress(): unspent["amount"] + 1
            }], 0, {"add_inputs": True})
        complete_psbt = self.nodes[0].walletprocesspsbt(psbtx_info["psbt"])
        double_processed_psbt = self.nodes[0].walletprocesspsbt(
            complete_psbt["psbt"])
        assert_equal(complete_psbt, double_processed_psbt)
        # We don't care about the decode result, but decoding must succeed.
        self.nodes[0].decodepsbt(double_processed_psbt["psbt"])

        # BIP 174 Test Vectors

        # Check that unknown values are just passed through
        unknown_psbt = "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAA="
        unknown_out = self.nodes[0].walletprocesspsbt(unknown_psbt)['psbt']
        assert_equal(unknown_psbt, unknown_out)

        # Open the data file
        with open(os.path.join(os.path.dirname(os.path.realpath(__file__)),
                               'data/rpc_psbt.json'),
                  encoding='utf-8') as f:
            d = json.load(f)
            invalids = d['invalid']
            valids = d['valid']
            creators = d['creator']
            signers = d['signer']
            combiners = d['combiner']
            finalizers = d['finalizer']
            extractors = d['extractor']

        # Invalid PSBTs
        for invalid in invalids:
            assert_raises_rpc_error(-22, "TX decode failed",
                                    self.nodes[0].decodepsbt, invalid)

        # Valid PSBTs
        for valid in valids:
            self.nodes[0].decodepsbt(valid)

        # Creator Tests
        for creator in creators:
            created_tx = self.nodes[0].createpsbt(creator['inputs'],
                                                  creator['outputs'])
            assert_equal(created_tx, creator['result'])

        # Signer tests
        for i, signer in enumerate(signers):
            self.nodes[2].createwallet("wallet{}".format(i))
            wrpc = self.nodes[2].get_wallet_rpc("wallet{}".format(i))
            for key in signer['privkeys']:
                wrpc.importprivkey(key)
            signed_tx = wrpc.walletprocesspsbt(signer['psbt'])['psbt']
            assert_equal(signed_tx, signer['result'])

        # Combiner test
        for combiner in combiners:
            combined = self.nodes[2].combinepsbt(combiner['combine'])
            assert_equal(combined, combiner['result'])

        # Empty combiner test
        assert_raises_rpc_error(-8, "Parameter 'txs' cannot be empty",
                                self.nodes[0].combinepsbt, [])

        # Finalizer test
        for finalizer in finalizers:
            finalized = self.nodes[2].finalizepsbt(finalizer['finalize'],
                                                   False)['psbt']
            assert_equal(finalized, finalizer['result'])

        # Extractor test
        for extractor in extractors:
            extracted = self.nodes[2].finalizepsbt(extractor['extract'],
                                                   True)['hex']
            assert_equal(extracted, extractor['result'])

        # Test decoding error: invalid base64
        assert_raises_rpc_error(-22, "TX decode failed invalid base64",
                                self.nodes[0].decodepsbt,
                                ";definitely not base64;")

        # Test that psbts with p2pkh outputs are created properly
        p2pkh = self.nodes[0].getnewaddress()
        psbt = self.nodes[1].walletcreatefundedpsbt([], [{
            p2pkh: 1
        }], 0, {"includeWatching": True}, True)
        self.nodes[0].decodepsbt(psbt['psbt'])

        # Send to all types of addresses
        addr1 = self.nodes[1].getnewaddress("")  # originally bech32
        txid1 = self.nodes[0].sendtoaddress(addr1, 11)
        vout1 = find_output(self.nodes[0], txid1, 11)
        addr2 = self.nodes[1].getnewaddress("")  # originally legacy
        txid2 = self.nodes[0].sendtoaddress(addr2, 11)
        vout2 = find_output(self.nodes[0], txid2, 11)
        addr3 = self.nodes[1].getnewaddress("")  # originally p2sh-segwit
        txid3 = self.nodes[0].sendtoaddress(addr3, 11)
        vout3 = find_output(self.nodes[0], txid3, 11)
        self.sync_all()

        def test_psbt_input_keys(psbt_input, keys):
            """Check that the psbt input has only the expected keys."""
            assert_equal(set(keys), set(psbt_input.keys()))

        # Create a PSBT. None of the inputs are filled initially
        psbt = self.nodes[1].createpsbt([{
            "txid": txid1,
            "vout": vout1
        }, {
            "txid": txid2,
            "vout": vout2
        }, {
            "txid": txid3,
            "vout": vout3
        }], {self.nodes[0].getnewaddress(): 32.999})
        decoded = self.nodes[1].decodepsbt(psbt)
        test_psbt_input_keys(decoded['inputs'][0], [])
        test_psbt_input_keys(decoded['inputs'][1], [])
        test_psbt_input_keys(decoded['inputs'][2], [])

        # Update a PSBT with UTXOs from the node
        updated = self.nodes[1].utxoupdatepsbt(psbt)
        decoded = self.nodes[1].decodepsbt(updated)
        test_psbt_input_keys(decoded['inputs'][1], [])
        test_psbt_input_keys(decoded['inputs'][2], [])

        # Try again, now while providing descriptors
        descs = [
            self.nodes[1].getaddressinfo(addr)['desc']
            for addr in [addr1, addr2, addr3]
        ]
        updated = self.nodes[1].utxoupdatepsbt(psbt=psbt, descriptors=descs)
        decoded = self.nodes[1].decodepsbt(updated)
        test_psbt_input_keys(decoded['inputs'][1], [])

        # Two PSBTs with a common input should not be joinable
        psbt1 = self.nodes[1].createpsbt(
            [{
                "txid": txid1,
                "vout": vout1
            }], {self.nodes[0].getnewaddress(): Decimal('10.999')})
        assert_raises_rpc_error(-8, "exists in multiple PSBTs",
                                self.nodes[1].joinpsbts, [psbt1, updated])

        # Join two distinct PSBTs
        addr4 = self.nodes[1].getnewaddress("")
        txid4 = self.nodes[0].sendtoaddress(addr4, 5)
        vout4 = find_output(self.nodes[0], txid4, 5)
        self.nodes[0].generate(6)
        self.sync_all()
        psbt2 = self.nodes[1].createpsbt(
            [{
                "txid": txid4,
                "vout": vout4
            }], {self.nodes[0].getnewaddress(): Decimal('4.999')})
        psbt2 = self.nodes[1].walletprocesspsbt(psbt2)['psbt']
        psbt2_decoded = self.nodes[0].decodepsbt(psbt2)
        assert "final_scriptSig" in psbt2_decoded['inputs'][0]
        joined = self.nodes[0].joinpsbts([psbt, psbt2])
        joined_decoded = self.nodes[0].decodepsbt(joined)
        assert len(joined_decoded['inputs']) == 4 and len(
            joined_decoded['outputs']
        ) == 2 and "final_scriptSig" not in joined_decoded['inputs'][3]

        # Fail when trying to join less than two PSBTs
        assert_raises_rpc_error(
            -8, "At least two PSBTs are required to join PSBTs.",
            self.nodes[1].joinpsbts, [])
        assert_raises_rpc_error(
            -8, "At least two PSBTs are required to join PSBTs.",
            self.nodes[1].joinpsbts, [psbt2])

        # Check that joining shuffles the inputs and outputs
        # 10 attempts should be enough to get a shuffled join
        shuffled = False
        for i in range(0, 10):
            shuffled_joined = self.nodes[0].joinpsbts([psbt, psbt2])
            shuffled |= joined != shuffled_joined
            if shuffled:
                break
        assert shuffled

        # Newly created PSBT needs UTXOs and updating
        addr = self.nodes[1].getnewaddress("")
        txid = self.nodes[0].sendtoaddress(addr, 7)
        blockhash = self.nodes[0].generate(6)[0]
        self.sync_all()
        vout = find_output(self.nodes[0], txid, 7, blockhash=blockhash)
        psbt = self.nodes[1].createpsbt(
            [{
                "txid": txid,
                "vout": vout
            }], {self.nodes[0].getnewaddress(""): Decimal('6.999')})
        analyzed = self.nodes[0].analyzepsbt(psbt)
        assert not analyzed['inputs'][0]['has_utxo'] and not analyzed[
            'inputs'][0]['is_final'] and analyzed['inputs'][0][
                'next'] == 'updater' and analyzed['next'] == 'updater'

        # After update with wallet, only needs signing
        updated = self.nodes[1].walletprocesspsbt(psbt, False, 'ALL|FORKID',
                                                  True)['psbt']
        analyzed = self.nodes[0].analyzepsbt(updated)
        assert analyzed['inputs'][0]['has_utxo'] and not analyzed['inputs'][0][
            'is_final'] and analyzed['inputs'][0][
                'next'] == 'signer' and analyzed['next'] == 'signer'

        # Check fee and size things
        assert analyzed['fee'] == Decimal(
            '0.001') and analyzed['estimated_vsize'] == 191 and analyzed[
                'estimated_feerate'] == Decimal('0.00523560')

        # After signing and finalizing, needs extracting
        signed = self.nodes[1].walletprocesspsbt(updated)['psbt']
        analyzed = self.nodes[0].analyzepsbt(signed)
        assert analyzed['inputs'][0]['has_utxo'] and analyzed['inputs'][0][
            'is_final'] and analyzed['next'] == 'extractor'

        self.log.info(
            "PSBT spending unspendable outputs should have error message and Creator as next"
        )
        analysis = self.nodes[0].analyzepsbt(
            'cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWAEHYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFv8/wADXYP/7//////8JxOh0LR2HAI8AAAAAAAEAIADC6wsAAAAAF2oUt/X69ELjeX2nTof+fZ10l+OyAokDAQcJAwEHEAABAACAAAEAIADC6wsAAAAAF2oUt/X69ELjeX2nTof+fZ10l+OyAokDAQcJAwEHENkMak8AAAAA'
        )
        assert_equal(analysis['next'], 'creator')
        assert_equal(analysis['error'],
                     'PSBT is not valid. Input 0 spends unspendable output')

        self.log.info(
            "PSBT with invalid values should have error message and Creator as next"
        )
        analysis = self.nodes[0].analyzepsbt(
            'cHNidP8BAHECAAAAAfA00BFgAm6tp86RowwH6BMImQNL5zXUcTT97XoLGz0BAAAAAAD/////AgD5ApUAAAAAFgAUKNw0x8HRctAgmvoevm4u1SbN7XL87QKVAAAAABYAFPck4gF7iL4NL4wtfRAKgQbghiTUAAAAAAABAB8AgIFq49AHABYAFJUDtxf2PHo641HEOBOAIvFMNTr2AAAA'
        )
        assert_equal(analysis['next'], 'creator')
        assert_equal(analysis['error'],
                     'PSBT is not valid. Input 0 has invalid value')

        analysis = self.nodes[0].analyzepsbt(
            'cHNidP8BAHECAAAAAfA00BFgAm6tp86RowwH6BMImQNL5zXUcTT97XoLGz0BAAAAAAD/////AgCAgWrj0AcAFgAUKNw0x8HRctAgmvoevm4u1SbN7XL87QKVAAAAABYAFPck4gF7iL4NL4wtfRAKgQbghiTUAAAAAAABAB8A8gUqAQAAABYAFJUDtxf2PHo641HEOBOAIvFMNTr2AAAA'
        )
        assert_equal(analysis['next'], 'creator')
        assert_equal(analysis['error'],
                     'PSBT is not valid. Output amount invalid')
예제 #23
0
    def run_test(self):
        # Mine some coins
        self.nodes[0].generate(110)

        # Get some addresses from the two nodes
        addr1 = [self.nodes[1].getnewaddress() for i in range(3)]
        addr2 = [self.nodes[2].getnewaddress() for i in range(3)]
        addrs = addr1 + addr2

        # Send 1 + 0.5 coin to each address
        [self.nodes[0].sendtoaddress(addr, 1000000) for addr in addrs]
        [self.nodes[0].sendtoaddress(addr, 500000) for addr in addrs]

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

        # For each node, send 0.2 coins back to 0;
        # - node[1] should pick one 0.5 UTXO and leave the rest
        # - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a
        #   given address, and leave the rest
        txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(),
                                            200000)
        tx1 = self.nodes[1].getrawtransaction(txid1, True)
        # txid1 should have 1 input and 2 outputs
        assert_equal(1, len(tx1["vin"]))
        assert_equal(2, len(tx1["vout"]))
        # one output should be 0.2, the other should be ~0.3
        v = sorted([vout["value"] for vout in tx1["vout"]])
        assert_approx(v[0], 200000)
        assert_approx(v[1], 300000, 100)

        txid2 = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(),
                                            200000)
        tx2 = self.nodes[2].getrawtransaction(txid2, True)
        # txid2 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx2["vin"]))
        assert_equal(2, len(tx2["vout"]))
        # one output should be 0.2, the other should be ~1.3
        v = sorted([vout["value"] for vout in tx2["vout"]])
        assert_approx(v[0], 200000)
        assert_approx(v[1], 1300000, 100)

        # Test 'avoid partial if warranted, even if disabled'
        self.sync_all()
        self.nodes[0].generate(1)
        # Nodes 1-2 now have confirmed UTXOs (letters denote destinations):
        # Node #1:      Node #2:
        # - A  1.0      - D0 1.0
        # - B0 1.0      - D1 0.5
        # - B1 0.5      - E0 1.0
        # - C0 1.0      - E1 0.5
        # - C1 0.5      - F  ~1.3
        # - D ~0.3
        assert_approx(self.nodes[1].getbalance(), 4300000, 100)
        assert_approx(self.nodes[2].getbalance(), 4300000, 100)
        # Sending 1.4 btc should pick one 1.0 + one more. For node #1,
        # this could be (A / B0 / C0) + (B1 / C1 / D). We ensure that it is
        # B0 + B1 or C0 + C1, because this avoids partial spends while not being
        # detrimental to transaction cost
        txid3 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(),
                                            1400000)
        tx3 = self.nodes[1].getrawtransaction(txid3, True)
        # tx3 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx3["vin"]))
        assert_equal(2, len(tx3["vout"]))
        # the accumulated value should be 1.5, so the outputs should be
        # ~0.1 and 1.4 and should come from the same destination
        values = sorted([vout["value"] for vout in tx3["vout"]])
        assert_approx(values[0], 100000, 100)
        assert_approx(values[1], 1400000)

        input_txids = [vin["txid"] for vin in tx3["vin"]]
        input_addrs = [
            self.nodes[1].gettransaction(txid)['details'][0]['address']
            for txid in input_txids
        ]
        assert_equal(input_addrs[0], input_addrs[1])
        # Node 2 enforces avoidpartialspends so needs no checking here

        # Test wallet option maxapsfee with Node 3
        addr_aps = self.nodes[3].getnewaddress()
        self.nodes[0].sendtoaddress(addr_aps, 1000000)
        self.nodes[0].sendtoaddress(addr_aps, 1000000)
        self.nodes[0].generate(1)
        self.sync_all()
        txid4 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(),
                                            100000)
        tx4 = self.nodes[3].getrawtransaction(txid4, True)
        # tx4 should have 2 inputs and 2 outputs although one output would
        # have been enough and the transaction caused higher fees
        assert_equal(2, len(tx4["vin"]))
        assert_equal(2, len(tx4["vout"]))

        # Empty out node2's wallet
        self.nodes[2].sendtoaddress(address=self.nodes[0].getnewaddress(),
                                    amount=self.nodes[2].getbalance(),
                                    subtractfeefromamount=True)
        self.sync_all()
        self.nodes[0].generate(1)

        # Fill node2's wallet with 10000 outputs corresponding to the same
        # scriptPubKey
        for i in range(5):
            raw_tx = self.nodes[0].createrawtransaction([{
                "txid": "0" * 64,
                "vout": 0
            }], [{
                addr2[0]: 50000
            }])
            tx = FromHex(CTransaction(), raw_tx)
            tx.vin = []
            tx.vout = [tx.vout[0]] * 2000
            funded_tx = self.nodes[0].fundrawtransaction(ToHex(tx))
            signed_tx = self.nodes[0].signrawtransactionwithwallet(
                funded_tx['hex'])
            self.nodes[0].sendrawtransaction(signed_tx['hex'])
            self.nodes[0].generate(1)

        self.sync_all()

        # Check that we can create a transaction that only requires ~100 of our
        # utxos, without pulling in all outputs and creating a transaction that
        # is way too big.
        assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5000000)
예제 #24
0
    def test_fund_send_fund_senddirty(self):
        '''
        Test the same as test_fund_send_fund_send, except send the 10 AUR with
        the avoid_reuse flag set to false. This means the 10 AUR send should succeed,
        where it fails in test_fund_send_fund_send.
        '''

        fundaddr = self.nodes[1].getnewaddress()
        retaddr = self.nodes[0].getnewaddress()

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 10 aur output
        assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0)
        # getbalances should show no used, 10 aur trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})
        # node 0 should not show a used entry, as it does not enable avoid_reuse
        assert("used" not in self.nodes[0].getbalances()["mine"])

        self.nodes[1].sendtoaddress(retaddr, 5)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 5 aur output
        assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0)
        # getbalances should show no used, 5 aur trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 2 total outputs (5, 10 aur), one unused (5), one reused (10)
        assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
        # getbalances should show 10 used, 5 aur trusted
        assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5}

        self.nodes[1].sendtoaddress(address=retaddr, amount=10, avoid_reuse=False)

        # listunspent should show 1 total outputs (5 aur), unused
        assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_count=0)
        # getbalances should show no used, 5 aur trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})

        # node 1 should now have about 5 aur left (for both cases)
        assert_approx(self.nodes[1].getbalance(), 5, 0.001)
        assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 5, 0.001)

    def test_fund_send_fund_send(self):
        '''
        Test the simple case where [1] generates a new address A, then
        [0] sends 10 AUR to A.
        [1] spends 5 AUR from A. (leaving roughly 5 BTC useable)
        [0] sends 10 AUR to A again.
        [1] tries to spend 10 AUR (fails; dirty).
        [1] tries to spend 4 AUR (succeeds; change address sufficient)
        '''

        fundaddr = self.nodes[1].getnewaddress()
        retaddr = self.nodes[0].getnewaddress()

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 10 aur output
        assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0)
        # getbalances should show no used, 10 aur trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})

        self.nodes[1].sendtoaddress(retaddr, 5)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 5 aur output
        assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0)
        # getbalances should show no used, 5 aur trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 2 total outputs (5, 10 aur), one unused (5), one reused (10)
        assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
        # getbalances should show 10 used, 5 aur trusted
        assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5})

        # node 1 should now have a balance of 5 (no dirty) or 15 (including dirty)
        assert_approx(self.nodes[1].getbalance(), 5, 0.001)
        assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 15, 0.001)

        assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[1].sendtoaddress, retaddr, 10)

        self.nodes[1].sendtoaddress(retaddr, 4)

        # listunspent should show 2 total outputs (1, 10 aur), one unused (1), one reused (10)
        assert_unspent(self.nodes[1], total_count=2, total_sum=11, reused_count=1, reused_sum=10)
        # getbalances should show 10 used, 1 aur trusted
        assert_balances(self.nodes[1], mine={"used": 10, "trusted": 1})

        # node 1 should now have about 1 aur left (no dirty) and 11 (including dirty)
        assert_approx(self.nodes[1].getbalance(), 1, 0.001)
        assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 11, 0.001)

if __name__ == '__main__':
    AvoidReuseTest().main()
예제 #25
0
    def run_test(self):
        # Mine some coins
        self.nodes[0].generate(110)

        # Get some addresses from the two nodes
        addr1 = [self.nodes[1].getnewaddress() for _ in range(3)]
        addr2 = [self.nodes[2].getnewaddress() for _ in range(3)]
        addrs = addr1 + addr2

        # Send 1 + 0.5 coin to each address
        [self.nodes[0].sendtoaddress(addr, 1000000) for addr in addrs]
        [self.nodes[0].sendtoaddress(addr, 500000) for addr in addrs]

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

        # For each node, send 0.2 coins back to 0;
        # - node[1] should pick one 0.5 UTXO and leave the rest
        # - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a
        #   given address, and leave the rest
        txid1 = self.nodes[1].sendtoaddress(
            self.nodes[0].getnewaddress(), 200000)
        tx1 = self.nodes[1].getrawtransaction(txid1, True)
        # txid1 should have 1 input and 2 outputs
        assert_equal(1, len(tx1["vin"]))
        assert_equal(2, len(tx1["vout"]))
        # one output should be 0.2, the other should be ~0.3
        v = sorted([vout["value"] for vout in tx1["vout"]])
        assert_approx(v[0], vexp=200_000, vspan=100)
        assert_approx(v[1], vexp=300_000, vspan=100)

        txid2 = self.nodes[2].sendtoaddress(
            self.nodes[0].getnewaddress(), 200000)
        tx2 = self.nodes[2].getrawtransaction(txid2, True)
        # txid2 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx2["vin"]))
        assert_equal(2, len(tx2["vout"]))
        # one output should be 0.2, the other should be ~1.3
        v = sorted([vout["value"] for vout in tx2["vout"]])
        assert_approx(v[0], vexp=200_000, vspan=100)
        assert_approx(v[1], vexp=1_300_000, vspan=100)

        # Test 'avoid partial if warranted, even if disabled'
        self.sync_all()
        self.nodes[0].generate(1)
        # Nodes 1-2 now have confirmed UTXOs (letters denote destinations):
        # Node #1:      Node #2:
        # - A  1.0      - D0 1.0
        # - B0 1.0      - D1 0.5
        # - B1 0.5      - E0 1.0
        # - C0 1.0      - E1 0.5
        # - C1 0.5      - F  ~1.3
        # - D ~0.3
        assert_approx(self.nodes[1].getbalance(), vexp=4_300_000, vspan=100)
        assert_approx(self.nodes[2].getbalance(), vexp=4_300_000, vspan=100)
        # Sending 1.4 btc should pick one 1.0 + one more. For node #1,
        # this could be (A / B0 / C0) + (B1 / C1 / D). We ensure that it is
        # B0 + B1 or C0 + C1, because this avoids partial spends while not being
        # detrimental to transaction cost
        txid3 = self.nodes[1].sendtoaddress(
            self.nodes[0].getnewaddress(), 1400000)
        tx3 = self.nodes[1].getrawtransaction(txid3, True)
        # tx3 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx3["vin"]))
        assert_equal(2, len(tx3["vout"]))
        # the accumulated value should be 1.5, so the outputs should be
        # ~0.1 and 1.4 and should come from the same destination
        values = sorted([vout["value"] for vout in tx3["vout"]])
        assert_approx(values[0], vexp=100_000, vspan=100)
        assert_approx(values[1], vexp=1_400_000, vspan=100)

        input_txids = [vin["txid"] for vin in tx3["vin"]]
        input_addrs = [self.nodes[1].gettransaction(
            txid)['details'][0]['address'] for txid in input_txids]
        assert_equal(input_addrs[0], input_addrs[1])
        # Node 2 enforces avoidpartialspends so needs no checking here

        # Test wallet option maxapsfee with Node 3
        addr_aps = self.nodes[3].getnewaddress()
        self.nodes[0].sendtoaddress(addr_aps, 1000000)
        self.nodes[0].sendtoaddress(addr_aps, 1000000)
        self.nodes[0].generate(1)
        self.sync_all()
        with self.nodes[3].assert_debug_log([
                'Fee non-grouped = 225, grouped = 372, using grouped']):
            txid4 = self.nodes[3].sendtoaddress(
                self.nodes[0].getnewaddress(), 100_000)
        tx4 = self.nodes[3].getrawtransaction(txid4, True)
        # tx4 should have 2 inputs and 2 outputs although one output would
        # have been enough and the transaction caused higher fees
        assert_equal(2, len(tx4["vin"]))
        assert_equal(2, len(tx4["vout"]))

        addr_aps2 = self.nodes[3].getnewaddress()
        [self.nodes[0].sendtoaddress(addr_aps2, 1_000_000) for _ in range(5)]
예제 #26
0
    def test_fund_send_fund_senddirty(self):
        '''
        Test the same as test_fund_send_fund_send, except send the 10 BTC with
        the avoid_reuse flag set to false. This means the 10 BTC send should succeed,
        where it fails in test_fund_send_fund_send.
        '''

        fundaddr = self.nodes[1].getnewaddress()
        retaddr = self.nodes[0].getnewaddress()

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 10 btc output
        assert_unspent(self.nodes[1],
                       total_count=1,
                       total_sum=10,
                       reused_supported=True,
                       reused_count=0)
        # getbalances should show no used, 10 btc trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})
        # node 0 should not show a used entry, as it does not enable avoid_reuse
        assert ("used" not in self.nodes[0].getbalances()["mine"])

        self.nodes[1].sendtoaddress(retaddr, 5)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 5 btc output
        assert_unspent(self.nodes[1],
                       total_count=1,
                       total_sum=5,
                       reused_supported=True,
                       reused_count=0)
        # getbalances should show no used, 5 btc trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})

        # For the second send, we transmute it to a related single-key address
        # to make sure it's also detected as re-use
        fund_spk = self.nodes[0].getaddressinfo(fundaddr)["scriptPubKey"]
        fund_decoded = self.nodes[0].decodescript(fund_spk)
        if second_addr_type == "p2sh-segwit":
            new_fundaddr = fund_decoded["segwit"]["p2sh-segwit"]
        elif second_addr_type == "bech32":
            new_fundaddr = fund_decoded["segwit"]["addresses"][0]
        else:
            new_fundaddr = fundaddr
            assert_equal(second_addr_type, "legacy")

        self.nodes[0].sendtoaddress(new_fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 2 total outputs (5, 10 btc), one unused (5), one reused (10)
        assert_unspent(self.nodes[1],
                       total_count=2,
                       total_sum=15,
                       reused_count=1,
                       reused_sum=10)
        # getbalances should show 10 used, 5 btc trusted
        assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5})

        self.nodes[1].sendtoaddress(address=retaddr,
                                    amount=10,
                                    avoid_reuse=False)

        # listunspent should show 1 total outputs (5 btc), unused
        assert_unspent(self.nodes[1],
                       total_count=1,
                       total_sum=5,
                       reused_count=0)
        # getbalances should show no used, 5 btc trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})

        # node 1 should now have about 5 btc left (for both cases)
        assert_approx(self.nodes[1].getbalance(), 5, 0.001)
        assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 5, 0.001)
예제 #27
0
    def test_sending_from_reused_address_fails(self, second_addr_type):
        '''
        Test the simple case where [1] generates a new address A, then
        [0] sends 10 ECC to A.
        [1] spends 5 ECC from A. (leaving roughly 5 ECC useable)
        [0] sends 10 ECC to A again.
        [1] tries to spend 10 ECC (fails; dirty).
        [1] tries to spend 4 ECC (succeeds; change address sufficient)
        '''
        self.log.info("Test sending from reused {} address fails".format(second_addr_type))

        fundaddr = self.nodes[1].getnewaddress(label="", address_type="legacy")
        retaddr = self.nodes[0].getnewaddress()

        self.nodes[0].sendtoaddress(fundaddr, 10)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 10 ecc output
        assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0)
        # getbalances should show no used, 10 ecc trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})

        self.nodes[1].sendtoaddress(retaddr, 5)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 5 ecc output
        assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0)
        # getbalances should show no used, 5 ecc trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})

        if not self.options.descriptors:
            # For the second send, we transmute it to a related single-key address
            # to make sure it's also detected as re-use
            fund_spk = self.nodes[0].getaddressinfo(fundaddr)["scriptPubKey"]
            fund_decoded = self.nodes[0].decodescript(fund_spk)
            if second_addr_type == "p2sh-segwit":
                new_fundaddr = fund_decoded["segwit"]["p2sh-segwit"]
            elif second_addr_type == "bech32":
                new_fundaddr = fund_decoded["segwit"]["addresses"][0]
            else:
                new_fundaddr = fundaddr
                assert_equal(second_addr_type, "legacy")

            self.nodes[0].sendtoaddress(new_fundaddr, 10)
            self.nodes[0].generate(1)
            self.sync_all()

            # listunspent should show 2 total outputs (5, 10 ecc), one unused (5), one reused (10)
            assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
            # getbalances should show 10 used, 5 ecc trusted
            assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5})

            # node 1 should now have a balance of 5 (no dirty) or 15 (including dirty)
            assert_approx(self.nodes[1].getbalance(), 5, 0.001)
            assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 15, 0.001)

            assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[1].sendtoaddress, retaddr, 10)

            self.nodes[1].sendtoaddress(retaddr, 4)

            # listunspent should show 2 total outputs (1, 10 ecc), one unused (1), one reused (10)
            assert_unspent(self.nodes[1], total_count=2, total_sum=11, reused_count=1, reused_sum=10)
            # getbalances should show 10 used, 1 ecc trusted
            assert_balances(self.nodes[1], mine={"used": 10, "trusted": 1})

            # node 1 should now have about 1 ecc left (no dirty) and 11 (including dirty)
            assert_approx(self.nodes[1].getbalance(), 1, 0.001)
            assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 11, 0.001)
    def run_test(self):
        self.M = 2
        self.N = self.num_nodes
        self.name = f"{self.M}_of_{self.N}_multisig"
        self.log.info(f"Testing {self.name}...")

        participants = {
            # Every participant generates an xpub. The most straightforward way is to create a new descriptor wallet.
            # This wallet will be the participant's `signer` for the resulting multisig. Avoid reusing this wallet for any other purpose (for privacy reasons).
            "signers": [
                node.get_wallet_rpc(
                    node.createwallet(
                        wallet_name=f"participant_{self.nodes.index(node)}",
                        descriptors=True)["name"]) for node in self.nodes
            ],
            # After participants generate and exchange their xpubs they will each create their own watch-only multisig.
            # Note: these multisigs are all the same, this just highlights that each participant can independently verify everything on their own node.
            "multisigs": []
        }

        self.log.info("Generate and exchange xpubs...")
        xpubs = [self._get_xpub(signer) for signer in participants["signers"]]

        self.log.info(
            "Every participant imports the following descriptors to create the watch-only multisig..."
        )
        participants["multisigs"] = list(
            self.participants_create_multisigs(xpubs))

        self.log.info(
            "Check that every participant's multisig generates the same addresses..."
        )
        for _ in range(
                10
        ):  # we check that the first 10 generated addresses are the same for all participant's multisigs
            receive_addresses = [
                multisig.getnewaddress()
                for multisig in participants["multisigs"]
            ]
            all(address == receive_addresses[0]
                for address in receive_addresses)
            change_addresses = [
                multisig.getrawchangeaddress()
                for multisig in participants["multisigs"]
            ]
            all(address == change_addresses[0] for address in change_addresses)

        self.log.info("Get a mature utxo to send to the multisig...")
        coordinator_wallet = participants["signers"][0]
        self.generatetoaddress(self.nodes[0], 101,
                               coordinator_wallet.getnewaddress())

        deposit_amount = 6.15
        multisig_receiving_address = participants["multisigs"][
            0].getnewaddress()
        self.log.info(
            "Send funds to the resulting multisig receiving address...")
        coordinator_wallet.sendtoaddress(multisig_receiving_address,
                                         deposit_amount)
        self.generate(self.nodes[0], 1)
        for participant in participants["multisigs"]:
            assert_approx(participant.getbalance(),
                          deposit_amount,
                          vspan=0.001)

        self.log.info("Send a transaction from the multisig!")
        to = participants["signers"][self.N - 1].getnewaddress()
        value = 1
        self.log.info(
            "First, make a sending transaction, created using `walletcreatefundedpsbt` (anyone can initiate this)..."
        )
        psbt = participants["multisigs"][0].walletcreatefundedpsbt(
            inputs=[], outputs={to: value}, options={"feeRate": 0.00010})

        psbts = []
        self.log.info(
            "Now at least M users check the psbt with decodepsbt and (if OK) signs it with walletprocesspsbt..."
        )
        for m in range(self.M):
            signers_multisig = participants["multisigs"][m]
            self._check_psbt(psbt["psbt"], to, value, signers_multisig)
            signing_wallet = participants["signers"][m]
            partially_signed_psbt = signing_wallet.walletprocesspsbt(
                psbt["psbt"])
            psbts.append(partially_signed_psbt["psbt"])

        self.log.info(
            "Finally, collect the signed PSBTs with combinepsbt, finalizepsbt, then broadcast the resulting transaction..."
        )
        combined = coordinator_wallet.combinepsbt(psbts)
        finalized = coordinator_wallet.finalizepsbt(combined)
        coordinator_wallet.sendrawtransaction(finalized["hex"])

        self.log.info(
            "Check that balances are correct after the transaction has been included in a block."
        )
        self.generate(self.nodes[0], 1)
        assert_approx(participants["multisigs"][0].getbalance(),
                      deposit_amount - value,
                      vspan=0.001)
        assert_equal(participants["signers"][self.N - 1].getbalance(), value)

        self.log.info(
            "Send another transaction from the multisig, this time with a daisy chained signing flow (one after another in series)!"
        )
        psbt = participants["multisigs"][0].walletcreatefundedpsbt(
            inputs=[], outputs={to: value}, options={"feeRate": 0.00010})
        for m in range(self.M):
            signers_multisig = participants["multisigs"][m]
            self._check_psbt(psbt["psbt"], to, value, signers_multisig)
            signing_wallet = participants["signers"][m]
            psbt = signing_wallet.walletprocesspsbt(psbt["psbt"])
            assert_equal(psbt["complete"], m == self.M - 1)
        finalized = coordinator_wallet.finalizepsbt(psbt["psbt"])
        coordinator_wallet.sendrawtransaction(finalized["hex"])

        self.log.info(
            "Check that balances are correct after the transaction has been included in a block."
        )
        self.generate(self.nodes[0], 1)
        assert_approx(participants["multisigs"][0].getbalance(),
                      deposit_amount - (value * 2),
                      vspan=0.001)
        assert_equal(participants["signers"][self.N - 1].getbalance(),
                     value * 2)
예제 #29
0
def assert_balances(node, mine):
    '''Make assertions about a node's getbalances output'''
    got = node.getbalances()["mine"]
    for k,v in mine.items():
        assert_approx(got[k], v, 0.001)
예제 #30
0
    def test_fund_send_fund_senddirty(self):
        '''
        Test the same as test_fund_send_fund_send, except send the 10 BTC with
        the avoid_reuse flag set to false. This means the 10 BTC send should succeed,
        where it fails in test_fund_send_fund_send.
        '''
        self.log.info("Test fund send fund send dirty")

        fundaddr = self.nodes[1].getnewaddress()
        retaddr = self.nodes[0].getnewaddress()

        self.nodes[0].sendtoaddress(fundaddr, 0.2)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 10 btc output
        assert_unspent(self.nodes[1],
                       total_count=1,
                       total_sum=0.2,
                       reused_supported=True,
                       reused_count=0)
        # getbalances should show no used, 10 btc trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 0.2})
        # node 0 should not show a used entry, as it does not enable avoid_reuse
        assert ("used" not in self.nodes[0].getbalances()["mine"])

        self.nodes[1].sendtoaddress(retaddr, 0.1)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 1 single, unused 5 btc output
        assert_unspent(self.nodes[1],
                       total_count=1,
                       total_sum=0.1,
                       reused_supported=True,
                       reused_count=0)
        # getbalances should show no used, 5 btc trusted
        assert_balances(self.nodes[1], mine={"used": 0, "trusted": 0.1})

        self.nodes[0].sendtoaddress(fundaddr, 0.2)
        self.nodes[0].generate(1)
        self.sync_all()

        # listunspent should show 2 total outputs (5, 10 btc), one unused (5), one reused (10)
        assert_unspent(self.nodes[1],
                       total_count=2,
                       total_sum=0.3,
                       reused_count=1,
                       reused_sum=0.2)
        # getbalances should show 10 used, 5 btc trusted
        assert_balances(self.nodes[1], mine={"used": 0.2, "trusted": 0.1})

        self.nodes[1].sendtoaddress(address=retaddr,
                                    amount=0.09,
                                    avoid_reuse=False)

        # listunspent should show 1 total outputs (5 btc), unused
        assert_unspent(self.nodes[1],
                       total_count=2,
                       total_sum=0.21,
                       reused_count=1)
        # getbalances should show no used, 5 btc trusted
        assert_balances(self.nodes[1], mine={"used": 0.2, "trusted": 0.009})

        # node 1 should now have about 5 btc left (for both cases)
        assert_approx(self.nodes[1].getbalance(), 0.01, 0.01)
        assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 0.2, 0.1)