def get_addresses(self, change, from_index, count):
     """Returns addresses from this deterministic wallet"""
     addrs = self._derive_addresses(change, from_index, count)
     spks = [address_to_script(a, self.rpc) for a in addrs]
     for index, spk in enumerate(spks):
         self.scriptpubkey_index[spk] = (change, from_index + index)
     self.next_index[change] = max(self.next_index[change],
                                   from_index + count)
     return addrs, spks
Ejemplo n.º 2
0
def get_scriptpubkeys_to_monitor(rpc, config):
    logger = logging.getLogger('ELECTRUMPERSONALSERVER')
    st = time.time()
    try:
        imported_addresses = set(
            rpc.call("getaddressesbyaccount",
                     [deterministicwallet.ADDRESSES_LABEL]))
        logger.debug("using deprecated accounts interface")
    except JsonRpcError:
        #bitcoin core 0.17 deprecates accounts, replaced with labels
        if deterministicwallet.ADDRESSES_LABEL in rpc.call("listlabels", []):
            imported_addresses = set(
                rpc.call("getaddressesbylabel",
                         [deterministicwallet.ADDRESSES_LABEL]).keys())
        else:
            #no label, no addresses imported at all
            imported_addresses = set()

    deterministic_wallets = []
    for key in config.options("master-public-keys"):
        mpk = config.get("master-public-keys", key)
        gaplimit = int(config.get("bitcoin-rpc", "gap_limit"))
        chain = rpc.call("getblockchaininfo", [])["chain"]
        try:
            wal = deterministicwallet.parse_electrum_master_public_key(
                mpk, gaplimit, rpc, chain)
        except ValueError:
            raise ValueError("Bad master public key format. Get it from " +
                             "Electrum menu `Wallet` -> `Information`")
        deterministic_wallets.append(wal)

    #check whether these deterministic wallets have already been imported
    import_needed = False
    wallets_to_import = []
    TEST_ADDR_COUNT = 3
    logger.info("Displaying first " + str(TEST_ADDR_COUNT) + " addresses of " +
                "each master public key:")
    for config_mpk_key, wal in zip(config.options("master-public-keys"),
                                   deterministic_wallets):
        first_addrs, first_spk = wal.get_addresses(change=0,
                                                   from_index=0,
                                                   count=TEST_ADDR_COUNT)
        logger.info("\n" + config_mpk_key + " =>\n\t" +
                    "\n\t".join(first_addrs))
        last_addr, last_spk = wal.get_addresses(
            change=0,
            from_index=int(config.get("bitcoin-rpc", "initial_import_count")) -
            1,
            count=1)
        if not set(first_addrs + last_addr).issubset(imported_addresses):
            import_needed = True
            wallets_to_import.append(wal)
    logger.info("Obtaining bitcoin addresses to monitor . . .")
    #check whether watch-only addresses have been imported
    watch_only_addresses = []
    for key in config.options("watch-only-addresses"):
        watch_only_addresses.extend(
            config.get("watch-only-addresses", key).split(' '))
    watch_only_addresses = set(watch_only_addresses)
    watch_only_addresses_to_import = []
    if not watch_only_addresses.issubset(imported_addresses):
        import_needed = True
        watch_only_addresses_to_import = (watch_only_addresses -
                                          imported_addresses)

    if len(deterministic_wallets) == 0 and len(watch_only_addresses) == 0:
        logger.error("No master public keys or watch-only addresses have " +
                     "been configured at all. Exiting..")
        #import = true and none other params means exit
        return (True, None, None)

    #if addresses need to be imported then return them
    if import_needed:
        #TODO minus imported_addresses
        logger.info("Importing " + str(len(wallets_to_import)) +
                    " wallets and " +
                    str(len(watch_only_addresses_to_import)) +
                    " watch-only addresses into the Bitcoin node")
        time.sleep(5)
        return True, watch_only_addresses_to_import, wallets_to_import

    #test
    # importing one det wallet and no addrs, two det wallets and no addrs
    # no det wallets and some addrs, some det wallets and some addrs

    #at this point we know we dont need to import any addresses
    #find which index the deterministic wallets are up to
    spks_to_monitor = []
    for wal in deterministic_wallets:
        for change in [0, 1]:
            addrs, spks = wal.get_addresses(
                change, 0,
                int(config.get("bitcoin-rpc", "initial_import_count")))
            spks_to_monitor.extend(spks)
            #loop until one address found that isnt imported
            while True:
                addrs, spks = wal.get_new_addresses(change, count=1)
                if addrs[0] not in imported_addresses:
                    break
                spks_to_monitor.append(spks[0])
            wal.rewind_one(change)

    spks_to_monitor.extend(
        [hashes.address_to_script(addr, rpc) for addr in watch_only_addresses])
    et = time.time()
    logger.info("Obtained list of addresses to monitor in " + str(et - st) +
                "sec")
    return False, spks_to_monitor, deterministic_wallets
Ejemplo n.º 3
0
def get_scriptpubkeys_to_monitor(rpc, config):
    logger = logging.getLogger('ELECTRUMPERSONALSERVER')
    st = time.time()
    try:
        imported_addresses = set(rpc.call("getaddressesbyaccount",
            [transactionmonitor.ADDRESSES_LABEL]))
        logger.debug("using deprecated accounts interface")
    except JsonRpcError:
        #bitcoin core 0.17 deprecates accounts, replaced with labels
        if transactionmonitor.ADDRESSES_LABEL in rpc.call("listlabels", []):
            imported_addresses = set(rpc.call("getaddressesbylabel",
                [transactionmonitor.ADDRESSES_LABEL]).keys())
        else:
            #no label, no addresses imported at all
            imported_addresses = set()
    logger.debug("already-imported addresses = " + str(imported_addresses))

    deterministic_wallets = []
    for key in config.options("master-public-keys"):
        wal = deterministicwallet.parse_electrum_master_public_key(
            config.get("master-public-keys", key),
            int(config.get("bitcoin-rpc", "gap_limit")))
        deterministic_wallets.append(wal)

    #check whether these deterministic wallets have already been imported
    import_needed = False
    wallets_imported = 0
    spks_to_import = []
    TEST_ADDR_COUNT = 3
    logger.info("Displaying first " + str(TEST_ADDR_COUNT) + " addresses of " +
        "each master public key:")
    for config_mpk_key, wal in zip(config.options("master-public-keys"),
            deterministic_wallets):
        first_spks = wal.get_scriptpubkeys(change=0, from_index=0,
            count=TEST_ADDR_COUNT)
        first_addrs = [hashes.script_to_address(s, rpc) for s in first_spks]
        logger.info("\n" + config_mpk_key + " =>\n\t" + "\n\t".join(
            first_addrs))
        if not set(first_addrs).issubset(imported_addresses):
            import_needed = True
            wallets_imported += 1
            for change in [0, 1]:
                spks_to_import.extend(wal.get_scriptpubkeys(change, 0,
                    int(config.get("bitcoin-rpc", "initial_import_count"))))
    logger.info("Obtaining bitcoin addresses to monitor . . .")
    #check whether watch-only addresses have been imported
    watch_only_addresses = []
    for key in config.options("watch-only-addresses"):
        watch_only_addresses.extend(config.get("watch-only-addresses",
            key).split(' '))
    watch_only_addresses = set(watch_only_addresses)
    watch_only_addresses_to_import = []
    if not watch_only_addresses.issubset(imported_addresses):
        import_needed = True
        watch_only_addresses_to_import = (watch_only_addresses -
            imported_addresses)

    #if addresses need to be imported then return them
    if import_needed:
        addresses_to_import = [hashes.script_to_address(spk, rpc)
            for spk in spks_to_import]
        #TODO minus imported_addresses
        logger.info("Importing " + str(wallets_imported) + " wallets and " +
            str(len(watch_only_addresses_to_import)) + " watch-only " +
            "addresses into the Bitcoin node")
        time.sleep(5)
        return (True, addresses_to_import + list(
            watch_only_addresses_to_import), None)

    #test
    # importing one det wallet and no addrs, two det wallets and no addrs
    # no det wallets and some addrs, some det wallets and some addrs

    #at this point we know we dont need to import any addresses
    #find which index the deterministic wallets are up to
    spks_to_monitor = []
    for wal in deterministic_wallets:
        for change in [0, 1]:
            spks_to_monitor.extend(wal.get_scriptpubkeys(change, 0,
                int(config.get("bitcoin-rpc", "initial_import_count"))))
            #loop until one address found that isnt imported
            while True:
                spk = wal.get_new_scriptpubkeys(change, count=1)[0]
                spks_to_monitor.append(spk)
                if hashes.script_to_address(spk, rpc) not in imported_addresses:
                    break
            spks_to_monitor.pop()
            wal.rewind_one(change)

    spks_to_monitor.extend([hashes.address_to_script(addr, rpc)
        for addr in watch_only_addresses])
    et = time.time()
    logger.info("Obtained list of addresses to monitor in " + str(et - st)
        + "sec")
    return False, spks_to_monitor, deterministic_wallets