def get_validator(address) -> (dict, None):
    """
    Return json of desired validator node
    """

    if DEBUG:
        nodes = get_validators()
        # Get the right node
        node = next(
            filter(lambda node: node['operator_address'] == address, nodes),
            None)
        return node
    else:
        response = requests.get(VALIDATORS_ENDPOINT + "/" + address)

        if response.status_code != 200:
            if response.status_code == 500 and ('validator does not exist'
                                                in response.json().get(
                                                    'error', '')):
                return None
            else:
                logger.info("ConnectionError while requesting " +
                            NODE_INFO_ENDPOINT)
                raise ConnectionError

        node = response.json()
        return node['result']
def get_validators() -> (dict, None):
    """
    Return json of all validator nodes
    """

    if DEBUG:
        # Get local validator file
        response = requests.get(VALIDATORS_ENDPOINT)
        if response.status_code != 200:
            logger.info("ConnectionError while requesting " +
                        VALIDATORS_ENDPOINT)
            raise ConnectionError
        nodes = response.json()
        return nodes['result']
    else:
        response = requests.get(VALIDATORS_ENDPOINT)
        if response.status_code != 200:
            if not is_lcd_reachable():
                logger.info("ConnectionError while requesting " +
                            NODE_INFO_ENDPOINT)
                raise ConnectionError
            else:
                return None

        nodes = response.json()
        return nodes['result']
def try_message(context,
                chat_id,
                text,
                reply_markup=None,
                remove_job_when_blocked=True):
    """
    Send a message to a user.
    """

    try:
        context.bot.send_message(chat_id,
                                 text,
                                 parse_mode='markdown',
                                 reply_markup=reply_markup,
                                 disable_web_page_preview=True)
    except TelegramError as e:
        if 'bot was blocked by the user' in e.message:
            logger.info("Telegram user " + str(chat_id) +
                        " blocked me; removing him from the user list")
            del context.dispatcher.user_data[chat_id]
            del context.dispatcher.chat_data[chat_id]
            del context.dispatcher.persistence.user_data[chat_id]
            del context.dispatcher.persistence.chat_data[chat_id]

            # Somehow session.data does not get updated if all users block the bot.
            # That makes problems on bot restart. That's why we delete the file ourselves.
            if len(context.dispatcher.persistence.user_data
                   ) == 0 and os.path.exists("./storage/session.data"):
                os.remove("./storage/session.data")

            if remove_job_when_blocked:
                context.job.schedule_removal()
        else:
            logger.error(e, exc_info=True)
            logger.info("Telegram user " + str(chat_id))
def on_vote_send_clicked(update, context):
    query = update.callback_query
    _, proposal_id, vote = query.data.split("-")
    proposal_title = context.user_data['proposals_cache'][proposal_id]['title']
    keyboard = [[
        InlineKeyboardButton(BACK_BUTTON_MSG,
                             callback_data=f'proposal-{proposal_id}-1')
    ]]

    try:
        vote_result = vote_delegated(proposal_id=proposal_id,
                                     vote=vote,
                                     telegram_user_id=query.from_user['id'])
        logger.info(f"Voted successfully. Transaction result:\n{vote_result}")
    except Exception as e:
        logger.exception(e)
        query.edit_message_text(NETWORK_ERROR_MSG,
                                reply_markup=InlineKeyboardMarkup(keyboard))
        return

    tx_hash = vote_result['result'].get('txhash', None)

    if tx_hash is None:
        text = f"Error while voting:\n{vote_result.get('result', None)}"
    else:
        text = f"Successfully voted *{vote}* on proposal *{proposal_title}*. 🎉\n" \
               f"See your vote here:\n" \
               f"{TERRA_FINDER_URL}tx/{tx_hash}"

    query.edit_message_text(text,
                            parse_mode='markdown',
                            reply_markup=InlineKeyboardMarkup(keyboard))
def is_node_catching_up():
    response = requests.get(url=NODE_STATUS_ENDPOINT)
    if response.status_code != 200:
        logger.info("ConnectionError while requesting " + NODE_STATUS_ENDPOINT)
        raise ConnectionError

    status = response.json()
    return status['result']['sync_info']['catching_up']
def get_node_block_height():
    """
    Return block height of your Terra Node
    """

    response = requests.get(url=NODE_STATUS_ENDPOINT)
    if response.status_code != 200:
        logger.info("ConnectionError while requesting " + NODE_STATUS_ENDPOINT)
        raise ConnectionError

    status = response.json()
    return status['result']['sync_info']['latest_block_height']
def main():
    """
    Init telegram bot, attach handlers and wait for incoming requests.
    """

    # Init telegram bot
    bot = Updater(TELEGRAM_BOT_TOKEN,
                  persistence=PicklePersistence(filename=session_data_path),
                  use_context=True)
    dispatcher = bot.dispatcher

    setup_existing_user(dispatcher=dispatcher)
    setup_sentry_jobs(dispatcher=dispatcher)

    dispatcher.add_handler(CommandHandler('start', start, run_async=True))
    dispatcher.add_handler(CommandHandler('cancel', cancel, run_async=True))
    dispatcher.add_handler(CallbackQueryHandler(dispatch_query,
                                                run_async=True))
    dispatcher.add_handler(
        MessageHandler(Filters.text, plain_input, run_async=True))

    # Start the bot
    bot.start_polling()
    logger.info(BOT_STARTUP_MSG)
    logger.info(f"""
    ==========================================================================
    ==========================================================================
    Debug: {DEBUG}
    Telegram bot token: {"SET" if TELEGRAM_BOT_TOKEN else "MISSING!"}
    Slack webhook: {SLACK_WEBHOOK}
    LCD endpoint: {LCD_ENDPOINT}
    Sentry nodes: {SENTRY_NODES}
    Node IP: {NODE_IP}
    ==========================================================================
    ==========================================================================
    """)
    # Run the bot until you press Ctrl-C or the process receives SIGINT,
    # SIGTERM or SIGABRT. This should be used most of the time, since
    # start_polling() is non-blocking and will stop the bot gracefully.
    bot.idle()
def setup_existing_user(dispatcher):
    """
    Tasks to ensure smooth user experience for existing users upon Bot restart
    """

    chat_ids = dispatcher.user_data.keys()
    delete_chat_ids = []
    for chat_id in chat_ids:
        try:
            dispatcher.bot.send_message(chat_id, BOT_RESTARTED_MSG)
            dispatcher.job_queue.run_repeating(
                node_checks,
                interval=JOB_INTERVAL_IN_SECONDS,
                context={
                    'chat_id': chat_id,
                    'user_data': dispatcher.user_data[chat_id]
                })
        except TelegramError as e:
            if 'bot was blocked by the user' in e.message:
                delete_chat_ids.append(chat_id)
                continue
            else:
                logger.error("Got Error\n" + str(e) + "\nwith telegram user " +
                             str(chat_id))

    for chat_id in delete_chat_ids:
        logger.info("Telegram user " + str(chat_id) +
                    " blocked me; removing him from the user list")
        del dispatcher.user_data[chat_id]
        del dispatcher.chat_data[chat_id]
        del dispatcher.persistence.user_data[chat_id]
        del dispatcher.persistence.chat_data[chat_id]

        # Somehow session.data does not get updated if all users block the bot.
        # That's why we delete the file ourselves.
        if len(dispatcher.persistence.user_data) == 0 and os.path.exists(
                session_data_path):
            os.remove(session_data_path)
def get_price_feed_prevotes(address):
    """
    Return the current prevotes oracle json
    """

    if DEBUG:
        # Get local prevotes file
        response = requests.get('http://localhost:8000/prevotes.json')
        if response.status_code != 200:
            logger.info(
                "ConnectionError while requesting http://localhost:8000/prevotes.json"
            )
            raise ConnectionError
        return response.json()
    else:
        response = requests.get('https://lcd.terra.dev/oracle/voters/' +
                                address + '/prevotes')
        if response.status_code != 200:
            logger.info(
                "ConnectionError while requesting https://lcd.terra.dev/oracle/voters/"
                + address + "/prevotes")
            raise ConnectionError
        return response.json()