'Load new blocks using RPC.  Requires running *coind supporting
getblockhash, getblock with verbose=false, and optionally
getrawmempool/getrawtransaction (to load mempool tx). Requires
chain_id in the datadir table.'

def catch_up_rpc(store, dircfg):

    chain_id = dircfg['chain_id']
    if (chain_id is None):
        store.log.error('no    chain_id')
        return False
    chain = store.chains_by.id[chain_id]
    conffile = (dircfg.get('conf') or chain.datadir_conf_file_name)
    conffile = os.path.join(dircfg['dirname'], conffile)
    try:
        conf = dict([(line.strip().split('=', 1) if ('=' in line) else (line.strip(), True)) for line in open(conffile) if ((line != '') and (line[0] not in '#\r\n'))])
    except Exception as e:
        store.log.error('failed    to    load    %s:    %s', conffile, e)
        return False
    rpcuser = conf.get('rpcuser', '')
    rpcpassword = conf['rpcpassword']
    rpcconnect = conf.get('rpcconnect', '127.0.0.1')
    rpcport = conf.get('rpcport', chain.datadir_rpcport)
    url = ((((((('http://' + rpcuser) + ':') + rpcpassword) + '@') + rpcconnect) + ':') + str(rpcport))
    ds = BCDataStream.BCDataStream()
    def rpc(func, *params):
        store.rpclog.info('RPC>>    %s    %s', func, params)
        ret = util.jsonrpc(url, func, *params)
        if store.rpclog.isEnabledFor(logging.INFO):
            store.rpclog.info('RPC<<    %s', re.sub('\\[[^\\]]{100,}\\]', '[...]', str(ret)))
        return ret
    def get_blockhash(height):
        try:
            return rpc('getblockhash', height)
        except util.JsonrpcException as e:
            if (e.code in ((-1), (-5), (-8))):
                return None
            raise
    height = (store.get_block_number(chain.id) + 1)
    def get_tx(rpc_tx_hash):
        try:
            rpc_tx_hex = rpc('getrawtransaction', rpc_tx_hash)
        except util.JsonrpcException as e:
            if (e.code != (-5)):
                raise
            if (height != 0):
                return None
            import genesis_tx
            rpc_tx_hex = genesis_tx.get(rpc_tx_hash)
            if (rpc_tx_hex is None):
                store.log.error('genesis    transaction    unavailable    via    RPC;    see    import-tx    in    abe.conf')
                return None
        rpc_tx = rpc_tx_hex.decode('hex')
        tx_hash = rpc_tx_hash.decode('hex')[::(-1)]
        computed_tx_hash = chain.transaction_hash(rpc_tx)
        if (tx_hash != computed_tx_hash):
            store.log.warn('transaction    hash    mismatch:    %r    !=    %r', tx_hash, computed_tx_hash)
        tx = chain.parse_transaction(rpc_tx)
        tx['hash'] = tx_hash
        return tx
    def first_new_block(height, next_hash):
        'Find    the    first    new    block.'
        while (height > 0):
            hash = get_blockhash((height - 1))
            if ((hash is not None) and ((1,) == store.selectrow('\n                                                                                SELECT    1\n                                                                                        FROM    chain_candidate    cc\n                                                                                        JOIN    block    b    ON    (cc.block_id    =    b.block_id)\n                                                                                    WHERE    b.block_hash    =    ?\n                                                                                            AND    b.block_height    IS    NOT    NULL\n                                                                                            AND    cc.chain_id    =    ?', (store.hashin_hex(str(hash)), chain.id)))):
                break
            next_hash = hash
            height -= 1
        return (height, next_hash)
    def catch_up_mempool(height):
        imported_tx = set()
        height_chk = (time.time() + 1)
        while store.rpc_load_mempool:
            for rpc_tx_hash in rpc('getrawmempool'):
                if (rpc_tx_hash in imported_tx):
                    continue
                if (height_chk < time.time()):
                    rpc_hash = get_blockhash(height)
                    if rpc_hash:
                        return rpc_hash
                    height_chk = (time.time() + 1)
                tx = get_tx(rpc_tx_hash)
                if (tx is None):
                    store.log.info(('tx    %s    gone    from    mempool' % rpc_tx_hash))
                    continue
                tx_id = store.tx_find_id_and_value(tx, False, check_only=True)
                if (tx_id is None):
                    tx_id = store.import_tx(tx, False, chain)
                    store.log.info('mempool    tx    %d', tx_id)
                    store.imported_bytes(tx['size'])
                imported_tx.add(rpc_tx_hash)
            store.clean_unlinked_tx(imported_tx)
            store.log.info('mempool    load    completed,    starting    over...')
            time.sleep(3)
        return None
    try:
        try:
            next_hash = get_blockhash(height)
        except util.JsonrpcException as e:
            raise
        except Exception as e:
            store.log.error('RPC    failed:    %s', e)
            return False
        (height, next_hash) = first_new_block(height, next_hash)
        rpc_hash = (next_hash or get_blockhash(height))
        if (rpc_hash is None):
            rpc_hash = catch_up_mempool(height)
        while (rpc_hash is not None):
            hash = rpc_hash.decode('hex')[::(-1)]
            if store.offer_existing_block(hash, chain.id):
                rpc_hash = get_blockhash((height + 1))
            else:
                ds.write(rpc('getblock', rpc_hash, False).decode('hex'))
                block_hash = chain.ds_block_header_hash(ds)
                block = chain.ds_parse_block(ds)
                assert (hash == block_hash)
                block['hash'] = block_hash
                if (chain.block_header_hash(chain.serialize_block_header(block)) != hash):
                    raise InvalidBlock('block    hash    mismatch')
                store.import_block(block, chain=chain)
                store.imported_bytes(ds.read_cursor)
                ds.clear()
                rpc_hash = get_blockhash((height + 1))
            height += 1
            if (rpc_hash is None):
                rpc_hash = catch_up_mempool(height)
                if rpc_hash:
                    (height, rpc_hash) = first_new_block(height, rpc_hash)
    except util.JsonrpcMethodNotFound as e:
        store.log.error('bitcoind    %s    not    supported', e.method)
        return False
    except InvalidBlock as e:
        store.log.error('RPC    data    not    understood:    %s', e)
        return False
    return True
