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