def test_device_wallets(bitcoin_regtest, devices_filled_data_folder, device_manager):
    wm = WalletManager(
        200100,
        devices_filled_data_folder,
        bitcoin_regtest.get_rpc(),
        "regtest",
        device_manager,
        allow_threading=False,
    )
    device = device_manager.get_by_alias("trezor")
    assert len(device.wallets(wm)) == 0
    wallet = wm.create_wallet("a_test_wallet", 1, "wpkh", [device.keys[5]], [device])
    assert len(device.wallets(wm)) == 1
    assert device.wallets(wm)[0].alias == wallet.alias
    second_device = device_manager.get_by_alias("specter")
    multisig_wallet = wm.create_wallet(
        "a_multisig_test_wallet",
        1,
        "wsh",
        [device.keys[7], second_device.keys[0]],
        [device, second_device],
    )

    assert len(device.wallets(wm)) == 2
    assert device.wallets(wm)[0].alias == wallet.alias
    assert device.wallets(wm)[1].alias == multisig_wallet.alias

    assert len(second_device.wallets(wm)) == 1
    assert second_device.wallets(wm)[0].alias == multisig_wallet.alias
Exemple #2
0
def test_wallet_change_addresses(bitcoin_regtest, devices_filled_data_folder, device_manager):
    wm = WalletManager(devices_filled_data_folder, bitcoin_regtest.get_cli(), "regtest", device_manager)
    # A wallet-creation needs a device
    device = device_manager.get_by_alias('specter')
    key = Key.from_json({
        "derivation": "m/48h/1h/0h/2h",
        "original": "Vpub5n9kKePTPPGtw3RddeJWJe29epEyBBcoHbbPi5HhpoG2kTVsSCUzsad33RJUt3LktEUUPPofcZczuudnwR7ZgkAkT6N2K2Z7wdyjYrVAkXM",
        "fingerprint": "08686ac6",
        "type": "wsh",
        "xpub": "tpubDFHpKypXq4kwUrqLotPs6fCic5bFqTRGMBaTi9s5YwwGymE8FLGwB2kDXALxqvNwFxB1dLWYBmmeFVjmUSdt2AsaQuPmkyPLBKRZW8BGCiL"
    })
    wallet = wm.create_wallet('a_second_test_wallet', 1, 'wpkh', [key], [device])

    address = wallet.address
    change_address = wallet.change_address
    assert wallet.addresses == [address]
    assert wallet.change_addresses == [change_address]
    assert wallet.active_addresses == [address]
    assert wallet.labels == ['Address #0']

    wallet.cli.generatetoaddress(20, change_address)
    random_address = "mruae2834buqxk77oaVpephnA5ZAxNNJ1r"
    wallet.cli.generatetoaddress(110, random_address)
    wallet.getdata()

    # new change address should be genrated automatically after receiving
    # assert wallet.change_addresses == [change_address, wallet.change_address]
    # This will not work here since Bitcoin Core doesn't count mining rewards in `getreceivedbyaddress`
    # See: https://github.com/bitcoin/bitcoin/issues/14654

    assert wallet.active_addresses == [address, change_address]
    # labels should return only active addresses
    assert wallet.labels == ['Address #0', 'Change #0']
Exemple #3
0
def test_wallet_change_addresses(bitcoin_regtest, devices_filled_data_folder,
                                 device_manager):
    wm = WalletManager(devices_filled_data_folder, bitcoin_regtest.get_rpc(),
                       "regtest", device_manager)
    # A wallet-creation needs a device
    device = device_manager.get_by_alias("specter")
    key = Key.from_json({
        "derivation":
        "m/48h/1h/0h/2h",
        "original":
        "Vpub5n9kKePTPPGtw3RddeJWJe29epEyBBcoHbbPi5HhpoG2kTVsSCUzsad33RJUt3LktEUUPPofcZczuudnwR7ZgkAkT6N2K2Z7wdyjYrVAkXM",
        "fingerprint":
        "08686ac6",
        "type":
        "wsh",
        "xpub":
        "tpubDFHpKypXq4kwUrqLotPs6fCic5bFqTRGMBaTi9s5YwwGymE8FLGwB2kDXALxqvNwFxB1dLWYBmmeFVjmUSdt2AsaQuPmkyPLBKRZW8BGCiL",
    })
    wallet = wm.create_wallet("a_second_test_wallet", 1, "wpkh", [key],
                              [device])

    address = wallet.address
    change_address = wallet.change_address
    assert wallet.addresses == [address]
    assert wallet.change_addresses == [change_address]

    wallet.rpc.generatetoaddress(20, change_address)
    random_address = "mruae2834buqxk77oaVpephnA5ZAxNNJ1r"
    wallet.rpc.generatetoaddress(110, random_address)
    wallet.getdata()
Exemple #4
0
def test_wallet_sortedmulti(bitcoin_regtest, devices_filled_data_folder, device_manager):
    wm = WalletManager(devices_filled_data_folder, bitcoin_regtest.get_cli(), "regtest", device_manager)
    device = device_manager.get_by_alias('trezor')
    second_device = device_manager.get_by_alias('specter')
    for i in range(2):
        if i == 0:
            multisig_wallet = wm.create_wallet('a_multisig_test_wallet', 1, 'wsh', [device.keys[7], second_device.keys[0]], [device, second_device])
        else:
            multisig_wallet = wm.create_wallet('a_multisig_test_wallet', 1, 'wsh', [second_device.keys[0], device.keys[7]], [second_device, device])

        address = multisig_wallet.address
        address_info = multisig_wallet.cli.getaddressinfo(address)
        assert address_info['pubkeys'][0] < address_info['pubkeys'][1]
        
        another_address = multisig_wallet.getnewaddress()
        another_address_info = multisig_wallet.cli.getaddressinfo(another_address)
        assert another_address_info['pubkeys'][0] < another_address_info['pubkeys'][1]
        
        third_address = multisig_wallet.get_address(30)
        third_address_info = multisig_wallet.cli.getaddressinfo(third_address)
        assert third_address_info['pubkeys'][0] < third_address_info['pubkeys'][1]

        change_address = multisig_wallet.change_address
        change_address_info = multisig_wallet.cli.getaddressinfo(change_address)
        assert change_address_info['pubkeys'][0] < change_address_info['pubkeys'][1]

        another_change_address = multisig_wallet.get_address(30, change=True)
        another_change_address_info = multisig_wallet.cli.getaddressinfo(another_change_address)
        assert another_change_address_info['pubkeys'][0] < another_change_address_info['pubkeys'][1]
Exemple #5
0
def test_wallet_createpsbt(bitcoin_regtest, devices_filled_data_folder, device_manager):
    wm = WalletManager(devices_filled_data_folder, bitcoin_regtest.get_cli(), "regtest", device_manager)
    # A wallet-creation needs a device
    device = device_manager.get_by_alias('specter')
    key = Key.from_json({
        "derivation": "m/48h/1h/0h/2h",
        "original": "Vpub5n9kKePTPPGtw3RddeJWJe29epEyBBcoHbbPi5HhpoG2kTVsSCUzsad33RJUt3LktEUUPPofcZczuudnwR7ZgkAkT6N2K2Z7wdyjYrVAkXM",
        "fingerprint": "08686ac6",
        "type": "wsh",
        "xpub": "tpubDFHpKypXq4kwUrqLotPs6fCic5bFqTRGMBaTi9s5YwwGymE8FLGwB2kDXALxqvNwFxB1dLWYBmmeFVjmUSdt2AsaQuPmkyPLBKRZW8BGCiL"
    })
    wallet = wm.create_wallet('a_second_test_wallet', 1, 'wpkh', [key], [device])
    # Let's fund the wallet with ... let's say 40 blocks a 50 coins each --> 200 coins
    address = wallet.getnewaddress()
    assert address == 'bcrt1qtnrv2jpygx2ef3zqfjhqplnycxak2m6ljnhq6z'
    wallet.cli.generatetoaddress(20, address)
    # in two addresses
    address = wallet.getnewaddress()
    wallet.cli.generatetoaddress(20, address)
    # newly minted coins need 100 blocks to get spendable
    # let's mine another 100 blocks to get these coins spendable
    random_address = "mruae2834buqxk77oaVpephnA5ZAxNNJ1r"
    wallet.cli.generatetoaddress(110, random_address)
    # update the wallet data
    wallet.get_balance()
    # Now we have loads of potential inputs
    # Let's spend 500 coins
    assert wallet.fullbalance >= 250
    # From this print-statement, let's grab some txids which we'll use for coinselect
    unspents = wallet.cli.listunspent(0)
    # Lets take 3 more or less random txs from the unspents:
    selected_coins = [
        "{},{},{}".format(unspents[5]['txid'], unspents[5]['vout'], unspents[5]['amount']), 
        "{},{},{}".format(unspents[9]['txid'], unspents[9]['vout'], unspents[9]['amount']),
        "{},{},{}".format(unspents[12]['txid'], unspents[12]['vout'], unspents[12]['amount'])
    ]
    selected_coins_amount_sum = unspents[5]['amount'] + unspents[9]['amount'] + unspents[12]['amount']
    number_of_coins_to_spend = selected_coins_amount_sum - 0.1 # Let's spend almost all of them 
    psbt = wallet.createpsbt([random_address], [number_of_coins_to_spend], True, 10, selected_coins=selected_coins)
    assert len(psbt['tx']['vin']) == 3
    psbt_txs = [ tx['txid'] for tx in psbt['tx']['vin'] ]
    for coin in selected_coins:
        assert coin.split(",")[0] in psbt_txs

    # Now let's spend more coins than we have selected. This should result in an exception:
    try:
        psbt = wallet.createpsbt([random_address], [number_of_coins_to_spend +1], True, 10, selected_coins=selected_coins)
        assert False, "should throw an exception!"
    except SpecterError as e:
        pass

    assert wallet.locked_amount == selected_coins_amount_sum
    assert len(wallet.cli.listlockunspent()) == 3
    assert wallet.full_available_balance == wallet.fullbalance - selected_coins_amount_sum

    wallet.delete_pending_psbt(psbt['tx']['txid'])
    assert wallet.locked_amount == 0
    assert len(wallet.cli.listlockunspent()) == 0
    assert wallet.full_available_balance == wallet.fullbalance
Exemple #6
0
def test_wallet_labeling(bitcoin_regtest, devices_filled_data_folder,
                         device_manager):
    wm = WalletManager(devices_filled_data_folder, bitcoin_regtest.get_rpc(),
                       "regtest", device_manager)
    # A wallet-creation needs a device
    device = device_manager.get_by_alias("specter")
    key = Key.from_json({
        "derivation":
        "m/48h/1h/0h/2h",
        "original":
        "Vpub5n9kKePTPPGtw3RddeJWJe29epEyBBcoHbbPi5HhpoG2kTVsSCUzsad33RJUt3LktEUUPPofcZczuudnwR7ZgkAkT6N2K2Z7wdyjYrVAkXM",
        "fingerprint":
        "08686ac6",
        "type":
        "wsh",
        "xpub":
        "tpubDFHpKypXq4kwUrqLotPs6fCic5bFqTRGMBaTi9s5YwwGymE8FLGwB2kDXALxqvNwFxB1dLWYBmmeFVjmUSdt2AsaQuPmkyPLBKRZW8BGCiL",
    })
    wallet = wm.create_wallet("a_second_test_wallet", 1, "wpkh", [key],
                              [device])

    address = wallet.address
    assert wallet.getlabel(address) == "Address #0"
    wallet.setlabel(address, "Random label")
    assert wallet.getlabel(address) == "Random label"

    wallet.rpc.generatetoaddress(20, address)

    random_address = "mruae2834buqxk77oaVpephnA5ZAxNNJ1r"
    wallet.rpc.generatetoaddress(100, random_address)

    # update utxo
    wallet.getdata()
    # update balance
    wallet.get_balance()

    address_balance = wallet.fullbalance
    assert len(wallet.utxo) == 20

    new_address = wallet.getnewaddress()
    wallet.setlabel(new_address, "")
    wallet.rpc.generatetoaddress(20, new_address)

    random_address = "mruae2834buqxk77oaVpephnA5ZAxNNJ1r"
    wallet.rpc.generatetoaddress(100, random_address)

    wallet.getdata()
    wallet.get_balance()

    assert len(wallet.utxo) == 40

    wallet.setlabel(new_address, "")
    third_address = wallet.getnewaddress()

    wallet.getdata()
    assert sorted(wallet.addresses) == sorted(
        [address, new_address, third_address])
Exemple #7
0
def test_WalletManager(bitcoin_regtest, devices_filled_data_folder,
                       device_manager):
    wm = WalletManager(devices_filled_data_folder, bitcoin_regtest.get_rpc(),
                       "regtest", device_manager)
    # A wallet-creation needs a device
    device = device_manager.get_by_alias("trezor")
    assert device != None
    # Lets's create a wallet with the WalletManager
    wm.create_wallet("a_test_wallet", 1, "wpkh", [device.keys[5]], [device])
    # The wallet-name gets its filename and therefore its alias
    wallet = wm.wallets["a_test_wallet"]
    assert wallet != None
    assert wallet.balance["trusted"] == 0
    assert wallet.balance["untrusted_pending"] == 0
    # this is a sum of both
    assert wallet.fullbalance == 0
    address = wallet.getnewaddress()
    # newly minted coins need 100 blocks to get spendable
    wallet.rpc.generatetoaddress(1, address)
    # let's mine another 100 blocks to get these coins spendable
    random_address = "mruae2834buqxk77oaVpephnA5ZAxNNJ1r"
    wallet.rpc.generatetoaddress(100, random_address)
    # update the balance
    wallet.get_balance()
    assert wallet.fullbalance >= 25

    # You can create a multisig wallet with the wallet manager like this
    second_device = device_manager.get_by_alias("specter")
    multisig_wallet = wm.create_wallet(
        "a_multisig_test_wallet",
        1,
        "wsh",
        [device.keys[7], second_device.keys[0]],
        [device, second_device],
    )

    assert len(wm.wallets) == 2
    assert multisig_wallet != None
    assert multisig_wallet.fullbalance == 0
    multisig_address = multisig_wallet.getnewaddress()
    multisig_wallet.rpc.generatetoaddress(1, multisig_address)
    multisig_wallet.rpc.generatetoaddress(100, random_address)
    # update balance
    multisig_wallet.get_balance()
    assert multisig_wallet.fullbalance >= 12.5
    # The WalletManager also has a `wallets_names` property, returning a sorted list of the names of all wallets
    assert wm.wallets_names == ["a_multisig_test_wallet", "a_test_wallet"]

    # You can rename a wallet using the wallet manager using `rename_wallet`, passing the wallet object and the new name to assign to it
    wm.rename_wallet(multisig_wallet, "new_name_test_wallet")
    assert multisig_wallet.name == "new_name_test_wallet"
    assert wm.wallets_names == ["a_test_wallet", "new_name_test_wallet"]

    # you can also delete a wallet by passing it to the wallet manager's `delete_wallet` method
    # it will delete the json and attempt to remove it from Bitcoin Core
    wallet_fullpath = multisig_wallet.fullpath
    assert os.path.exists(wallet_fullpath)
    wm.delete_wallet(multisig_wallet)
    assert not os.path.exists(wallet_fullpath)
    assert len(wm.wallets) == 1
def test_wallet_sortedmulti(
    bitcoin_regtest, devices_filled_data_folder, device_manager
):
    wm = WalletManager(
        200100,
        devices_filled_data_folder,
        bitcoin_regtest.get_rpc(),
        "regtest",
        device_manager,
        allow_threading=False,
    )
    device = device_manager.get_by_alias("trezor")
    second_device = device_manager.get_by_alias("specter")
    for i in range(2):
        if i == 0:
            multisig_wallet = wm.create_wallet(
                "a_multisig_test_wallet",
                1,
                "wsh",
                [device.keys[7], second_device.keys[0]],
                [device, second_device],
            )
        else:
            multisig_wallet = wm.create_wallet(
                "a_multisig_test_wallet",
                1,
                "wsh",
                [second_device.keys[0], device.keys[7]],
                [second_device, device],
            )

        address = multisig_wallet.address
        address_info = multisig_wallet.rpc.getaddressinfo(address)
        assert address_info["pubkeys"][0] < address_info["pubkeys"][1]

        another_address = multisig_wallet.getnewaddress()
        another_address_info = multisig_wallet.rpc.getaddressinfo(another_address)
        assert another_address_info["pubkeys"][0] < another_address_info["pubkeys"][1]

        third_address = multisig_wallet.get_address(30)
        third_address_info = multisig_wallet.rpc.getaddressinfo(third_address)
        assert third_address_info["pubkeys"][0] < third_address_info["pubkeys"][1]

        change_address = multisig_wallet.change_address
        change_address_info = multisig_wallet.rpc.getaddressinfo(change_address)
        assert change_address_info["pubkeys"][0] < change_address_info["pubkeys"][1]

        another_change_address = multisig_wallet.get_address(30, change=True)
        another_change_address_info = multisig_wallet.rpc.getaddressinfo(
            another_change_address
        )
        assert (
            another_change_address_info["pubkeys"][0]
            < another_change_address_info["pubkeys"][1]
        )
def test_WalletManager(bitcoin_regtest, devices_filled_data_folder,
                       device_manager):
    wm = WalletManager(devices_filled_data_folder, bitcoin_regtest.get_cli(),
                       "regtest", device_manager)
    # A wallet-creation needs a device
    device = device_manager.get_by_alias('trezor')
    assert device != None
    # Lets's create a wallet with the WalletManager
    wm.create_wallet('a_test_wallet', 1, 'wpkh', [device.keys[5]], [device])
    # The wallet-name gets its filename and therefore its alias
    wallet = wm.wallets['a_test_wallet']
    assert wallet != None
    assert wallet.balance['trusted'] == 0
    assert wallet.balance['untrusted_pending'] == 0
    # this is a sum of both
    assert wallet.fullbalance == 0
    address = wallet.getnewaddress()
    # newly minted coins need 100 blocks to get spendable
    wallet.cli.generatetoaddress(1, address)
    # let's mine another 100 blocks to get these coins spendable
    random_address = "mruae2834buqxk77oaVpephnA5ZAxNNJ1r"
    wallet.cli.generatetoaddress(100, random_address)
    # a balance has properties which are caching the result from last call
    assert wallet.fullbalance == 50

    # You can create a multisig wallet with the wallet manager like this
    second_device = device_manager.get_by_alias('specter')
    multisig_wallet = wm.create_wallet('a_multisig_test_wallet', 1, 'wsh',
                                       [device.keys[7], second_device.keys[0]],
                                       [device, second_device])

    assert len(wm.wallets) == 2
    assert multisig_wallet != None
    assert multisig_wallet.fullbalance == 0
    multisig_address = multisig_wallet.getnewaddress()
    multisig_wallet.cli.generatetoaddress(1, multisig_address)
    multisig_wallet.cli.generatetoaddress(100, random_address)
    # a balance has properties which are caching the result from last call
    assert multisig_wallet.fullbalance == 25
    # The WalletManager also has a `wallets_names` property, returning a sorted list of the names of all wallets
    assert wm.wallets_names == ['a_multisig_test_wallet', 'a_test_wallet']

    # You can rename a wallet using the wallet manager using `rename_wallet`, passing the wallet object and the new name to assign to it
    wm.rename_wallet(multisig_wallet, 'new_name_test_wallet')
    assert multisig_wallet.name == 'new_name_test_wallet'
    assert wm.wallets_names == ['a_test_wallet', 'new_name_test_wallet']

    # you can also delete a wallet by passing it to the wallet manager's `delete_wallet` method
    # it will delete the json and attempt to remove it from Bitcoin Core
    wallet_fullpath = multisig_wallet.fullpath
    assert os.path.exists(wallet_fullpath)
    wm.delete_wallet(multisig_wallet)
    assert not os.path.exists(wallet_fullpath)
    assert len(wm.wallets) == 1
def test_device_wallets(bitcoin_regtest, devices_filled_data_folder,
                        device_manager):
    wm = WalletManager(devices_filled_data_folder, bitcoin_regtest.get_cli(),
                       "regtest", device_manager)
    device = device_manager.get_by_alias('trezor')
    assert len(device.wallets(wm)) == 0
    wallet = wm.create_wallet('a_test_wallet', 1, 'wpkh', [device.keys[5]],
                              [device])
    assert len(device.wallets(wm)) == 1
    assert device.wallets(wm)[0].alias == wallet.alias
    second_device = device_manager.get_by_alias('specter')
    multisig_wallet = wm.create_wallet('a_multisig_test_wallet', 1, 'wsh',
                                       [device.keys[7], second_device.keys[0]],
                                       [device, second_device])

    assert len(device.wallets(wm)) == 2
    assert device.wallets(wm)[0].alias == wallet.alias
    assert device.wallets(wm)[1].alias == multisig_wallet.alias

    assert len(second_device.wallets(wm)) == 1
    assert second_device.wallets(wm)[0].alias == multisig_wallet.alias
def test_abandon_purged_tx(caplog, docker, request, devices_filled_data_folder,
                           device_manager):
    # Specter should support calling abandontransaction if a pending tx has been purged
    # from the mempool. Test starts a new bitcoind with a restricted mempool to make it
    # easier to spam the mempool and purge our target tx.
    # TODO: Similar test but for maxmempoolexpiry?

    # Copied and adapted from:
    #    https://github.com/bitcoin/bitcoin/blob/master/test/functional/mempool_limit.py
    from bitcoin_core.test.functional.test_framework.util import (
        gen_return_txouts,
        satoshi_round,
        create_lots_of_big_transactions,
    )
    from conftest import instantiate_bitcoind_controller

    caplog.set_level(logging.DEBUG)

    # ==== Specter-specific: do custom setup ====
    # Instantiate a new bitcoind w/limited mempool. Use a different port to not interfere
    # with existing instance for other tests.
    bitcoind_controller = instantiate_bitcoind_controller(
        docker,
        request,
        rpcport=18998,
        extra_args=[
            "-acceptnonstdtxn=1", "-maxmempool=5", "-spendzeroconfchange=0"
        ],
    )
    rpcconn = bitcoind_controller.rpcconn
    rpc = rpcconn.get_rpc()
    assert rpc is not None
    assert rpc.ipaddress != None

    # Note: Our utxo creation is simpler than mempool_limit.py's approach since we're
    # running in regtest and can just use generatetoaddress().

    # Instantiate a new Specter instance to talk to this bitcoind
    config = {
        "rpc": {
            "autodetect": False,
            "user": rpcconn.rpcuser,
            "password": rpcconn.rpcpassword,
            "port": rpcconn.rpcport,
            "host": rpcconn.ipaddress,
            "protocol": "http",
        },
        "auth": {
            "method": "rpcpasswordaspin",
        },
    }
    specter = Specter(data_folder=devices_filled_data_folder, config=config)
    specter.check()

    specter.check_node_info()
    assert specter._info["mempool_info"][
        "maxmempool"] == 5 * 1000 * 1000  # 5MB

    # Largely copy-and-paste from test_wallet_manager.test_wallet_createpsbt.
    # TODO: Make a test fixture in conftest.py that sets up already funded wallets
    # for a bitcoin core hot wallet.
    wallet_manager = WalletManager(
        200100,
        devices_filled_data_folder,
        rpc,
        "regtest",
        device_manager,
    )

    # Create a new device that can sign psbts (Bitcoin Core hot wallet)
    device = device_manager.add_device(name="bitcoin_core_hot_wallet",
                                       device_type="bitcoincore",
                                       keys=[])
    device.setup_device(file_password=None, wallet_manager=wallet_manager)
    device.add_hot_wallet_keys(
        mnemonic=generate_mnemonic(strength=128),
        passphrase="",
        paths=["m/49h/0h/0h"],
        file_password=None,
        wallet_manager=wallet_manager,
        testnet=True,
        keys_range=[0, 1000],
        keys_purposes=[],
    )

    wallet = wallet_manager.create_wallet("bitcoincore_test_wallet", 1,
                                          "sh-wpkh", [device.keys[0]],
                                          [device])

    # Fund the wallet. Going to need a LOT of utxos to play with.
    logging.info("Generating utxos to wallet")
    address = wallet.getnewaddress()
    wallet.rpc.generatetoaddress(91, address)

    # newly minted coins need 100 blocks to get spendable
    # let's mine another 100 blocks to get these coins spendable
    wallet.rpc.generatetoaddress(101, address)

    # update the wallet data
    wallet.get_balance()

    # ==== Begin test from mempool_limit.py ====
    txouts = gen_return_txouts()
    relayfee = satoshi_round(rpc.getnetworkinfo()["relayfee"])

    logging.info("Check that mempoolminfee is minrelytxfee")
    assert satoshi_round(
        rpc.getmempoolinfo()["minrelaytxfee"]) == Decimal("0.00001000")
    assert satoshi_round(
        rpc.getmempoolinfo()["mempoolminfee"]) == Decimal("0.00001000")

    txids = []
    utxos = wallet.rpc.listunspent()

    logging.info("Create a mempool tx that will be evicted")
    us0 = utxos.pop()
    inputs = [{"txid": us0["txid"], "vout": us0["vout"]}]
    outputs = {wallet.getnewaddress(): 0.0001}
    tx = wallet.rpc.createrawtransaction(inputs, outputs)
    wallet.rpc.settxfee(
        str(relayfee))  # specifically fund this tx with low fee
    txF = wallet.rpc.fundrawtransaction(tx)
    wallet.rpc.settxfee(0)  # return to automatic fee selection
    txFS = device.sign_raw_tx(txF["hex"], wallet)
    txid = wallet.rpc.sendrawtransaction(txFS["hex"])

    # ==== Specter-specific: can't abandon a valid pending tx ====
    try:
        wallet.abandontransaction(txid)
    except SpecterError as e:
        assert "Cannot abandon" in str(e)

    # ==== Resume test from mempool_limit.py ====
    # Spam the mempool with big transactions!
    relayfee = satoshi_round(rpc.getnetworkinfo()["relayfee"])
    base_fee = float(relayfee) * 100
    for i in range(3):
        txids.append([])
        txids[i] = create_lots_of_big_transactions(wallet, txouts,
                                                   utxos[30 * i:30 * i + 30],
                                                   30, (i + 1) * base_fee)

    logging.info("The tx should be evicted by now")
    assert txid not in wallet.rpc.getrawmempool()
    txdata = wallet.rpc.gettransaction(txid)
    assert txdata["confirmations"] == 0  # confirmation should still be 0

    # ==== Specter-specific: Verify purge and abandon ====
    assert wallet.is_tx_purged(txid)
    wallet.abandontransaction(txid)

    # tx will still be in the wallet but marked "abandoned"
    txdata = wallet.rpc.gettransaction(txid)
    for detail in txdata["details"]:
        if detail["category"] == "send":
            assert detail["abandoned"]

    # Can we now spend those same inputs?
    outputs = {wallet.getnewaddress(): 0.0001}
    tx = wallet.rpc.createrawtransaction(inputs, outputs)

    # Fund this tx with a high enough fee
    relayfee = satoshi_round(rpc.getnetworkinfo()["relayfee"])
    wallet.rpc.settxfee(str(relayfee * Decimal("3.0")))

    txF = wallet.rpc.fundrawtransaction(tx)
    wallet.rpc.settxfee(0)  # return to automatic fee selection
    txFS = device.sign_raw_tx(txF["hex"], wallet)
    txid = wallet.rpc.sendrawtransaction(txFS["hex"])

    # Should have been accepted by the mempool
    assert txid in wallet.rpc.getrawmempool()
    assert wallet.get_balance()["untrusted_pending"] == 0.0001

    # Clean up
    bitcoind_controller.stop_bitcoind()
Exemple #12
0
def test_wallet_labeling(bitcoin_regtest, devices_filled_data_folder, device_manager):
    wm = WalletManager(devices_filled_data_folder, bitcoin_regtest.get_cli(), "regtest", device_manager)
    # A wallet-creation needs a device
    device = device_manager.get_by_alias('specter')
    key = Key.from_json({
        "derivation": "m/48h/1h/0h/2h",
        "original": "Vpub5n9kKePTPPGtw3RddeJWJe29epEyBBcoHbbPi5HhpoG2kTVsSCUzsad33RJUt3LktEUUPPofcZczuudnwR7ZgkAkT6N2K2Z7wdyjYrVAkXM",
        "fingerprint": "08686ac6",
        "type": "wsh",
        "xpub": "tpubDFHpKypXq4kwUrqLotPs6fCic5bFqTRGMBaTi9s5YwwGymE8FLGwB2kDXALxqvNwFxB1dLWYBmmeFVjmUSdt2AsaQuPmkyPLBKRZW8BGCiL"
    })
    wallet = wm.create_wallet('a_second_test_wallet', 1, 'wpkh', [key], [device])

    address = wallet.address
    assert wallet.getlabel(address) == 'Address #0'
    wallet.setlabel(address, 'Random label')
    assert wallet.getlabel(address) == 'Random label'

    wallet.cli.generatetoaddress(20, address)

    random_address = "mruae2834buqxk77oaVpephnA5ZAxNNJ1r"
    wallet.cli.generatetoaddress(100, random_address)
    
    # update utxo
    wallet.getdata()
    # update balance
    wallet.get_balance()

    address_balance = wallet.fullbalance
    assert len(wallet.utxo) == 20
    assert wallet.is_current_address_used
    assert wallet.balance_on_address(address) == address_balance
    assert wallet.balance_on_label('Random label') == address_balance
    assert wallet.addresses_on_label('Random label') == [address]
    assert wallet.utxo_addresses == [address]
    assert wallet.utxo_labels == ['Random label']
    assert wallet.utxo_addresses == [address]

    new_address = wallet.getnewaddress()
    wallet.setlabel(new_address, '')
    wallet.cli.generatetoaddress(20, new_address)

    random_address = "mruae2834buqxk77oaVpephnA5ZAxNNJ1r"
    wallet.cli.generatetoaddress(100, random_address)

    wallet.getdata()
    wallet.get_balance()

    assert len(wallet.utxo) == 40
    assert wallet.is_current_address_used
    assert wallet.utxo_on_address(address) == 20
    assert wallet.balance_on_address(new_address) == wallet.fullbalance - address_balance
    assert sorted(wallet.utxo_addresses) == sorted([address, new_address])
    assert sorted(wallet.utxo_labels) == sorted(['Random label', new_address])
    assert sorted(wallet.utxo_addresses) == sorted([address, new_address])
    assert wallet.get_address_name(new_address, -1) == new_address
    assert wallet.get_address_name(new_address, 5) == 'Address #5'
    assert wallet.get_address_name(address, 5) == 'Random label'

    wallet.setlabel(new_address, '')
    third_address = wallet.getnewaddress()

    wallet.getdata()
    assert sorted(wallet.labels) == sorted(['Random label', new_address, 'Address #2'])
    assert sorted(wallet.utxo_labels) == sorted(['Random label', new_address])
    assert sorted(wallet.addresses) == sorted([address, new_address, third_address])
    assert sorted(wallet.utxo_addresses) == sorted([address, new_address])

    wallet.setlabel(third_address, 'Random label')
    wallet.getdata()
    assert sorted(wallet.addresses_on_label('Random label')) == sorted([address, third_address])