def check_for_new_txes(self):
        logger = self.logger
        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):
            ##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
        if len(ret) > 0:
            self.last_known_wallet_txid = (ret[0]["txid"],
                ret[0].get("address", None))
        assert(recent_tx_index != -1)
        if recent_tx_index == 0:
            return set()
        new_txes = ret[:recent_tx_index][::-1]
        logger.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", "generate",
                    "immature"):
                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 = 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():
                        new_addrs, spks = wal.get_new_addresses(change,
                            import_count)
                        for spk in spks:
                            self.address_history[script_to_scripthash(
                                spk)] =  {'history': [], 'subscribed': False}
                        logger.debug("importing " + str(len(spks)) +
                            " into change=" + str(change))
                        import_addresses(self.rpc, new_addrs, [], -1, 0, logger)

            updated_scripthashes.extend(matching_scripthashes)
            new_history_element = self.generate_new_history_element(tx, txd)
            logger.info("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)
예제 #2
0
def main():
    opts = parse_args()

    try:
        config = RawConfigParser()
        config.read(opts.config_file)
        config.options("master-public-keys")
    except NoSectionError:
        print("ERROR: Non-existant configuration file {}".format(
            opts.config_file))
        return
    logger = logging.getLogger('ELECTRUMPERSONALSERVER')
    logger, logfilename = logger_config(logger, config)
    logger.info('Starting Electrum Personal Server ' +
                str(SERVER_VERSION_NUMBER))
    logger.info('Logging to ' + logfilename)
    logger.debug("Process ID (PID) = " + str(os.getpid()))
    rpc_u = None
    rpc_p = None
    cookie_path = None
    try:
        rpc_u = config.get("bitcoin-rpc", "rpc_user")
        rpc_p = config.get("bitcoin-rpc", "rpc_password")
        logger.debug("obtaining auth from rpc_user/pass")
    except NoOptionError:
        cookie_path = obtain_cookie_file_path(
            config.get("bitcoin-rpc", "datadir"))
        logger.debug("obtaining auth from .cookie")
    if rpc_u == None and cookie_path == None:
        return
    rpc = JsonRpc(host=config.get("bitcoin-rpc", "host"),
                  port=int(config.get("bitcoin-rpc", "port")),
                  user=rpc_u,
                  password=rpc_p,
                  cookie_path=cookie_path,
                  wallet_filename=config.get("bitcoin-rpc",
                                             "wallet_filename").strip(),
                  logger=logger)

    #TODO somewhere here loop until rpc works and fully sync'd, to allow
    # people to run this script without waiting for their node to fully
    # catch up sync'd when getblockchaininfo blocks == headers, or use
    # verificationprogress
    printed_error_msg = False
    while bestblockhash[0] == None:
        try:
            bestblockhash[0] = rpc.call("getbestblockhash", [])
        except JsonRpcError as e:
            if not printed_error_msg:
                logger.error("Error with bitcoin json-rpc: " + repr(e))
                printed_error_msg = True
            time.sleep(5)
    try:
        rpc.call("listunspent", [])
    except JsonRpcError as e:
        logger.error(repr(e))
        logger.error("Wallet related RPC call failed, possibly the " +
                     "bitcoin node was compiled with the disable wallet flag")
        return

    test_keydata = (
        "2 tpubD6NzVbkrYhZ4YVMVzC7wZeRfz3bhqcHvV8M3UiULCfzFtLtp5nwvi6LnBQegrkx"
        +
        "YGPkSzXUEvcPEHcKdda8W1YShVBkhFBGkLxjSQ1Nx3cJ tpubD6NzVbkrYhZ4WjgNYq2nF"
        +
        "TbiSLW2SZAzs4g5JHLqwQ3AmR3tCWpqsZJJEoZuP5HAEBNxgYQhtWMezszoaeTCg6FWGQB"
        + "T74sszGaxaf64o5s")
    chain = rpc.call("getblockchaininfo", [])["chain"]
    try:
        gaplimit = 5
        deterministicwallet.parse_electrum_master_public_key(
            test_keydata, gaplimit, rpc, chain)
    except ValueError as e:
        logger.error(repr(e))
        logger.error(
            "Descriptor related RPC call failed. Bitcoin Core 0.20.0" +
            " or higher required. Exiting..")
        return
    if opts.rescan:
        rescan_script(logger, rpc, opts.rescan_date)
        return
    while True:
        logger.debug("Checking whether rescan is in progress")
        walletinfo = rpc.call("getwalletinfo", [])
        if "scanning" in walletinfo and walletinfo["scanning"]:
            logger.debug("Waiting for Core wallet rescan to finish")
            time.sleep(300)
            continue
        break
    import_needed, relevant_spks_addrs, deterministic_wallets = \
        get_scriptpubkeys_to_monitor(rpc, config)
    if import_needed:
        if not relevant_spks_addrs and not deterministic_wallets:
            #import = true and no addresses means exit
            return
        deterministicwallet.import_addresses(
            rpc,
            relevant_spks_addrs,
            deterministic_wallets,
            change_param=-1,
            count=int(config.get("bitcoin-rpc", "initial_import_count")))
        logger.info(
            "Done.\nIf recovering a wallet which already has existing" +
            " transactions, then\nrun the rescan script. If you're confident" +
            " that the wallets are new\nand empty then there's no need to" +
            " rescan, just restart this script")
    else:
        txmonitor = transactionmonitor.TransactionMonitor(
            rpc, deterministic_wallets, logger)
        if not txmonitor.build_address_history(relevant_spks_addrs):
            return
        try:
            run_electrum_server(rpc, txmonitor, config)
        except KeyboardInterrupt:
            logger.info('Received KeyboardInterrupt, quitting')
def main():
    opts = parse_args()

    try:
        config = RawConfigParser()
        config.read(opts.config_file)
        config.options("master-public-keys")
    except NoSectionError:
        print("ERROR: Non-existant configuration file {}".format(
            opts.config_file))
        return 1
    logger = logging.getLogger('ELECTRUMPERSONALSERVER')
    logger, logfilename = logger_config(logger, config)
    logger.info('Starting Electrum Personal Server ' +
                str(SERVER_VERSION_NUMBER))
    logger.info('Logging to ' + logfilename)
    logger.debug("Process ID (PID) = " + str(os.getpid()))
    rpc_u = None
    rpc_p = None
    cookie_path = None
    try:
        rpc_u = config.get("groestlcoin-rpc", "rpc_user")
        rpc_p = config.get("groestlcoin-rpc", "rpc_password")
        logger.debug("obtaining auth from rpc_user/pass")
    except NoOptionError:
        cookie_path = obtain_cookie_file_path(
            config.get("groestlcoin-rpc", "datadir"))
        logger.debug("obtaining auth from .cookie")
    if rpc_u == None and cookie_path == None:
        return 1
    rpc = JsonRpc(host=config.get("groestlcoin-rpc", "host"),
                  port=int(config.get("groestlcoin-rpc", "port")),
                  user=rpc_u,
                  password=rpc_p,
                  cookie_path=cookie_path,
                  wallet_filename=config.get("groestlcoin-rpc",
                                             "wallet_filename").strip(),
                  logger=logger)

    #TODO somewhere here loop until rpc works and fully sync'd, to allow
    # people to run this script without waiting for their node to fully
    # catch up sync'd when getblockchaininfo blocks == headers, or use
    # verificationprogress
    printed_error_msg = False
    while bestblockhash[0] == None:
        try:
            bestblockhash[0] = rpc.call("getbestblockhash", [])
        except JsonRpcError as e:
            if not printed_error_msg:
                logger.error("Error with groestlcoin json-rpc: " + repr(e))
                printed_error_msg = True
            time.sleep(5)
    try:
        rpc.call("listunspent", [])
    except JsonRpcError as e:
        logger.error(repr(e))
        logger.error(
            "Wallet related RPC call failed, possibly the " +
            "groestlcoin node was compiled with the disable wallet flag")
        return 1

    test_keydata = (
        "2 tpubD6NzVbkrYhZ4Xh9Ybbw6cna2UyGzYXmpk6bYuvWAUsD493Eb57ssPKC74CoVyQi"
        +
        "thN9hRUKZz5c5BQqnS8zqDisJvDTA6fJgyVjhGFtSZaN tpubD6NzVbkrYhZ4XG7HrP7yo"
        +
        "9We8rEmc7RTbViHgKwYNwNN71gvuMpYDWRHCUoGMYKZvDMbF3VpWngHvbpTan9Wd3WTk9q"
        + "ZzZyuYKAGoPJRGjs")
    chain = rpc.call("getblockchaininfo", [])["chain"]
    try:
        gaplimit = 5
        deterministicwallet.parse_electrum_master_public_key(
            test_keydata, gaplimit, rpc, chain)
    except ValueError as e:
        logger.error(repr(e))
        logger.error(
            "Descriptor related RPC call failed. Groestlcoin Core 2.20.1" +
            " or higher required. Exiting..")
        return 1
    if opts.rescan:
        rescan_script(logger, rpc, opts.rescan_date)
        return 0
    while True:
        logger.debug("Checking whether rescan is in progress")
        walletinfo = rpc.call("getwalletinfo", [])
        if "scanning" in walletinfo and walletinfo["scanning"]:
            logger.debug("Waiting for Core wallet rescan to finish")
            time.sleep(300)
            continue
        break
    import_needed, relevant_spks_addrs, deterministic_wallets = \
        get_scriptpubkeys_to_monitor(rpc, config)
    if import_needed:
        if not relevant_spks_addrs and not deterministic_wallets:
            #import = true and no addresses means exit
            return 0
        deterministicwallet.import_addresses(
            rpc,
            relevant_spks_addrs,
            deterministic_wallets,
            change_param=-1,
            count=int(config.get("groestlcoin-rpc", "initial_import_count")))
        logger.info(
            "Done.\nIf recovering a wallet which already has existing" +
            " transactions, then\nrun the rescan script. If you're confident" +
            " that the wallets are new\nand empty then there's no need to" +
            " rescan, just restart this script")
    else:
        txmonitor = transactionmonitor.TransactionMonitor(
            rpc, deterministic_wallets, logger)
        if not txmonitor.build_address_history(relevant_spks_addrs):
            return 1
        try:
            run_electrum_server(rpc, txmonitor, config)
        except KeyboardInterrupt:
            logger.info('Received KeyboardInterrupt, quitting')
            return 1
    return 0