def get_scriptpubkeys_to_monitor(rpc, config): imported_addresses = set(rpc.call("getaddressesbyaccount", [transactionmonitor.ADDRESSES_LABEL])) 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 = [] for wal in deterministic_wallets: first_addr = hashes.script_to_address(wal.get_scriptpubkeys(change=0, from_index=0, count=1)[0], rpc) if first_addr not in 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")))) #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 log("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]) return False, spks_to_monitor, deterministic_wallets
def check_for_new_txes(self): MAX_TX_REQUEST_COUNT = 256 tx_request_count = 2 max_attempts = int(math.log(MAX_TX_REQUEST_COUNT, 2)) for i in range(max_attempts): self.debug("listtransactions tx_request_count=" + str(tx_request_count)) ##how listtransactions works ##skip and count parameters take most-recent txes first ## so skip=0 count=1 will return the most recent tx ##and skip=0 count=3 will return the 3 most recent txes ##but the actual list returned has the REVERSED order ##skip=0 count=3 will return a list with the most recent tx LAST ret = self.rpc.call("listtransactions", ["*", tx_request_count, 0, True]) ret = ret[::-1] if self.last_known_wallet_txid == None: recent_tx_index = len(ret) #=0 means no new txes break else: txid_list = [(tx["txid"], tx.get("address", None)) for tx in ret] recent_tx_index = next( (i for i, (txid, addr) in enumerate(txid_list) if txid == self.last_known_wallet_txid[0] and addr == self.last_known_wallet_txid[1]), -1) if recent_tx_index != -1: break tx_request_count *= 2 #TODO low priority: handle a user getting more than 255 new # transactions in 15 seconds self.debug("recent tx index = " + str(recent_tx_index) + " ret = " + str([(t["txid"], t.get("address", None)) for t in ret])) if len(ret) > 0: self.last_known_wallet_txid = (ret[0]["txid"], ret[0].get("address", None)) self.debug("last_known_wallet_txid = " + str(self.last_known_wallet_txid)) assert (recent_tx_index != -1) if recent_tx_index == 0: return set() new_txes = ret[:recent_tx_index][::-1] self.debug("new txes = " + str(new_txes)) obtained_txids = set() updated_scripthashes = [] for tx in new_txes: if "txid" not in tx or "category" not in tx: continue if tx["category"] not in ("receive", "send"): continue if tx["confirmations"] < 0: continue #conflicted if tx["txid"] in obtained_txids: continue obtained_txids.add(tx["txid"]) output_scriptpubkeys, input_scriptpubkeys, txd = \ self.get_input_and_output_scriptpubkeys(tx["txid"]) matching_scripthashes = [] for spk in (output_scriptpubkeys + input_scriptpubkeys): scripthash = hashes.script_to_scripthash(spk) if scripthash in self.address_history: matching_scripthashes.append(scripthash) if len(matching_scripthashes) == 0: continue for wal in self.deterministic_wallets: overrun_depths = wal.have_scriptpubkeys_overrun_gaplimit( output_scriptpubkeys) if overrun_depths != None: for change, import_count in overrun_depths.items(): spks = wal.get_new_scriptpubkeys(change, import_count) for spk in spks: self.address_history[hashes.script_to_scripthash( spk)] = { 'history': [], 'subscribed': False } new_addrs = [ hashes.script_to_address(s, self.rpc) for s in spks ] self.debug("importing " + str(len(spks)) + " into change=" + str(change)) import_addresses(self.rpc, new_addrs, self.debug, self.log) updated_scripthashes.extend(matching_scripthashes) new_history_element = self.generate_new_history_element(tx, txd) self.log("Found new tx: " + str(new_history_element)) for scrhash in matching_scripthashes: self.address_history[scrhash]["history"].append( new_history_element) if new_history_element["height"] == 0: self.unconfirmed_txes[tx["txid"]].append(scrhash) if tx["confirmations"] > 0: self.reorganizable_txes.append( (tx["txid"], tx["blockhash"], new_history_element["height"], matching_scripthashes)) return set(updated_scripthashes)