visit
cd ~
virtualenv -p python3.8 up_env # crete a virtualenv
source ~/up_env/bin/activate # activate the virtualenl
pip install python-telegram-bot
pip install "python-telegram-bot[job-queue]" --pre
pip install --upgrade python-telegram-bot==13.6.0 # the code was written before version 20, so here the version is explicitly specified
pip install numpy # needed for the median value function
pip install web3 # needed for requests to nodes (replace with what you need)
File with functions functions.py (you can implement it with classes, but since the example is short, I did not plan to divide it into modules, but a multi-threading library requires functions to be moved to a separate file). Import dependencies:
import numpy as np
import multiprocessing
from web3 import Web3 # add those libraries needed for your task
Describing a function for checking the state. In my case, it involved looping through pre-selected public nodes, retrieving their last block, taking the median value to filter out any deviations, and then, checking our own node against this median.
# Helper function that checks a single node
def get_last_block_once(rpc):
try:
w3 = Web3(Web3.HTTPProvider(rpc))
block_number = w3.eth.block_number
if isinstance(block_number, int):
return block_number
else:
return None
except Exception as e:
print(f'{rpc} - {repr(e)}')
return None
# Main function to check the status of the service that will be called
def check_service():
# pre-prepared list of reference nodes
# for any network, it can be found on the website //chainlist.org/
list_of_public_nodes = [
'//polygon.llamarpc.com',
'//polygon.rpc.blxrbdn.com',
'//polygon.blockpi.network/v1/rpc/public',
'//polygon-mainnet.public.blastapi.io',
'//rpc-mainnet.matic.quiknode.pro',
'//polygon-bor.publicnode.com',
'//poly-rpc.gateway.pokt.network',
'//rpc.ankr.com/polygon',
'//polygon-rpc.com'
]
# parallel processing of requests to all nodes
with multiprocessing.Pool(processes=len(list_of_public_nodes)) as pool:
results = pool.map(get_last_block_once, list_of_public_nodes)
last_blocks = [b for b in results if b is not None and isinstance(b, int)]
# define the maximum and median value of the current block
med_val = int(np.median(last_blocks))
max_val = int(np.max(last_blocks))
# determine the number of nodes with the maximum and median value
med_support = np.sum([1 for x in last_blocks if x == med_val])
max_support = np.sum([1 for x in last_blocks if x == max_val])
return max_val, max_support, med_val, med_support
The next important file of the bot is uptime_bot.py. We import libraries and functions from the file above and set the necessary constants:
import telegram
from telegram.ext import Updater, CommandHandler, Filters
from functions import get_last_block_once, check_service
# Here one can to set a limited circle of bot users,
# listing the usernames of the users
ALLOWED_USERS = ['your_telegram_account', 'someone_else']
# The address of the node that I am monitoring (also a public node in this case)
OBJECT_OF_CHECKING = '//polygon-mainnet.chainstacklabs.com'
# Threshold for highlighting critical lag
THRESHOLD = 5
def start(update, context):
"""Send a message when the command /start is issued."""
try:
# Get the user
user = update.effective_user
# Filter out bots
if user.is_bot:
return
# Check if the user is allowed
username = str(user.username)
if username not in ALLOWED_USERS:
return
except Exception as e:
print(f'{repr(e)}')
return
# Call the main function to check the network status
max_val, max_support, med_val, med_support = check_service()
# Call the function to check the status of the specified node
last_block = get_last_block_once(OBJECT_OF_CHECKING)
# Create the message to send to Telegram
message = ""
# Information about the state of the nodes in the public network (median, maximum, and number of nodes)
message += f"Public median block number {med_val} (on {med_support}) RPCs\n"
message += f"Public maximum block number +{max_val - med_val} (on {max_support}) PRCs\n"
# Compare with the threshold
if last_block is not None:
out_text = str(last_block - med_val) if last_block - med_val < 0 else '+' + str(last_block - med_val)
if abs(last_block - med_val) > THRESHOLD:
message += f"The node block number shift ⚠️<b>{out_text}</b>⚠️"
else:
message += f"The node block number shift {out_text}"
else: # Exception processing if a node has not responded
message += f"The node has ⚠️<b>not responded</b>⚠️"
# Send the message to the user
context.bot.send_message(chat_id=user.id, text=message, parse_mode="HTML")
token = "xxx" # Bot token obtained from BotFather
# set up the bot
bot = telegram.Bot(token=token)
updater = Updater(token=token, use_context=True)
dispatcher = updater.dispatcher
# bind the handler function
dispatcher.add_handler(CommandHandler("start", start, filters=Filters.chat_type.private))
# run the bot
updater.start_polling()
source ~/up_env/bin/activate
python uptime_bot.py