Skip to content

Commit

Permalink
Merge pull request #33 from p2p-org/astar_network_onborading
Browse files Browse the repository at this point in the history
  • Loading branch information
SergeyRadchenkoP2P authored Mar 8, 2024
2 parents c0f1850 + 444f2ca commit 7308b9d
Show file tree
Hide file tree
Showing 24 changed files with 699 additions and 38 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ WS_ENDPOINTS="http://your-node1:9944,http://your-node2:9944,http://your-node3:99
2. Run the exporters, grafana and tg bot:
- directly via docker-compose:
- `docker-compose -f docker-compose.yml -f polkadot.yml -f kusama.yml up` - will start exporters for polkadot and kusama
- `docker-compose -f docker-compose.yml -f polkadot.yml -f kusama.yml -f acala.yml -f karura.yml -f moonbeam.yml -f moonriver.yml up` - will start exporters only for polkadot/kusama and parachains Acala/Karura, Moonbeam/Moonriver.
- `docker-compose -f docker-compose.yml -f polkadot.yml -f kusama.yml -f acala.yml -f karura.yml -f moonbeam.yml -f moonriver.yml -f astar.yml -f shiden.yml up` - will start exporters only for polkadot/kusama and parachains Acala/Karura, Moonbeam/Moonrive, Astar/Shiden.
3. Inspect the [dashboard](http://127.0.0.1:3000/d/fDrj0_EGz/p2p-org-polkadot-kusama-dashboard?orgId=1) (default username and password `admin``admin`)
4. Inspect the tg bot:
1. Contact with your bot. Command `/start` will be good:)
Expand Down
2 changes: 2 additions & 0 deletions astar.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
WS_ENDPOINT="wss://astar-rpc.dwellir.com"
WS_ENDPOINTS="wss://astar-rpc.dwellir.com"
15 changes: 15 additions & 0 deletions astar.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: '3.4'

services:
astar_exporter:
build:
context: ./exporters/astar
environment:
- "LISTEN=0.0.0.0"
- "PORT=9150"
- "CHAIN=astar"
env_file:
- ./astar.env
networks:
- exporters

38 changes: 34 additions & 4 deletions bot/alerts_tmpl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ rules:

- alert: "[Acala] Offline collators"
expr: |
rate(acala_session_active_validators{chain="acala", account=~"[[accounts]]"}[30m]) > 0
rate(acala_activeCollators{chain="acala", account=~"[[accounts]]"}[30m]) > 0
for: "[[interval]]"
labels:
uniqueid: 16
Expand All @@ -240,7 +240,7 @@ rules:

- alert: "[Karura] Offline collators"
expr: |
rate(acala_session_active_validators{chain="karura", account=~"[[accounts]]"}[30m]) > 0
rate(acala_activeCollators{chain="karura", account=~"[[accounts]]"}[30m]) > 0
for: "[[interval]]"
labels:
uniqueid: 17
Expand Down Expand Up @@ -312,13 +312,43 @@ rules:
description: "Collator {{ $labels.account }} is inactive now!"
chain: "{{ $labels.chain }}"
account: "{{ $labels.account }}"
bot_description: "Will shout if some of selected collators been an active and become to inactive."
bot_description: "Will shout if some of selected collators been an active and become to inactive."

- alert: "[Astar] Offline collators"
expr: |
rate(astar_activeCollators{chain="astar", account=~"[[accounts]]"}[30m]) > 0
for: "[[interval]]"
labels:
uniqueid: 22
chat_id: "[[chat_id]]"
labels_source: astar_activeCollators
annotations:
summary: "{{ $labels.chain }}: Collator become to inactive state!"
description: "Collator {{ $labels.account }} is inactive now!"
chain: "{{ $labels.chain }}"
account: "{{ $labels.account }}"
bot_description: "Will shout if some of selected collators been an active and become to inactive."

- alert: "[Shiden] Offline collators"
expr: |
rate(astar_activeCollators{chain="shiden", account=~"[[accounts]]"}[30m]) > 0
for: "[[interval]]"
labels:
uniqueid: 23
chat_id: "[[chat_id]]"
labels_source: astar_activeCollators
annotations:
summary: "{{ $labels.chain }}: Collator become to inactive state!"
description: "Collator {{ $labels.account }} is inactive now!"
chain: "{{ $labels.chain }}"
account: "{{ $labels.account }}"
bot_description: "Will shout if some of selected collators been an active and become to inactive."

- alert: "Test alert - FIRE NOW."
expr: vector(1)
for: "[[interval]]"
labels:
uniqueid: 22
uniqueid: 24
chat_id: "[[chat_id]]"
annotations:
summary: "This is a summary of test alert."
Expand Down
2 changes: 1 addition & 1 deletion bot/app/callback_query_handlers/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ async def acc_menu(query: CallbackQuery):

menu = MenuBuilder()

text = "Here you can mange accounts you would like to track.\n\nFor now we are processing over " + str(cache.count()) + " uniq accounts of validators and collators.\n\nNetworks covered:\n🔸Polkadot/Kusama\n🔸Acala/Karura\n🔸Moonbeam/Moonriver\n\n"
text = "Here you can mange accounts you would like to track.\n\nFor now we are processing over " + str(cache.count()) + " uniq accounts of validators and collators.\n\nNetworks covered:\n🔸Polkadot/Kusama\n🔸Acala/Karura\n🔸Moonbeam/Moonriver\n🔸Astar/Shiden\n\n"

if not validators:
text += "☝️ No accounts in portfolio yet."
Expand Down
2 changes: 1 addition & 1 deletion bot/app/callback_query_handlers/main_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ async def main_menu(message: Message):
if not account_status:
db.add_account(chat_id,username)

await bot.send_message(admin_chat, text="Username: @" + username + " ID:" + chat_id + "\n\nHas just registered.")
await bot.send_message(admin_chat, text="Username: @" + str(username) + " ID:" + str(chat_id) + "\n\nHas just registered.")

try:
await message.edit_text("✋✋✋ Welcome to a validator monitoring bot by P2P.org\n\nWe tried to collect lots of metrics related to validators behavior in substrate based networks and expose it through Telegram bot.\n\nNote: We collect metrics for one month, you can get historical data through Grafana.",reply_markup=menu.as_markup())
Expand Down
6 changes: 3 additions & 3 deletions bot/app/middlewares/acl.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ async def check_if_blocked(handler: Callable[[Update, Dict[str, Any]], Awaitable

account_status = db.get_records('account_status','id',chat_id)

if isinstance(account_status, list):
await bot.delete_message(chat_id, message_id)
CancelHandler()
#if isinstance(account_status, list):
# await bot.delete_message(chat_id, message_id)
# CancelHandler()

if account_status == 'off':
if event.event_type == 'message':
Expand Down
2 changes: 2 additions & 0 deletions calamari.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
WS_ENDPOINT="wss://ws.calamari.systems/"
WS_ENDPOINTS="wss://ws.calamari.systems/"
15 changes: 15 additions & 0 deletions calamari.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: '3.4'

services:
calamari_exporter:
build:
context: ./exporters/manta
environment:
- "LISTEN=0.0.0.0"
- "PORT=9150"
- "CHAIN=calamari"
env_file:
- ./manta.env
networks:
- exporters

53 changes: 25 additions & 28 deletions exporters/acala/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,28 @@ def metrics():
out = ""

try:
out += '# HELP acala_session_common Common metrics\n'
out += '# TYPE acala_session_common counter\n'
out += '# HELP acala_currentSession Current session\n'
out += '# TYPE acala_currentSession counter\n'

for k, v in metrics['common'].items():
out += 'acala_session_common{name="%s", chain="%s"} %s\n' % (k, chain, v)
out += 'acala_currentSession{chain="%s"} %s\n' % (chain, metrics['common']['current_session'])
except KeyError:
pass

try:
out += '# HELP acala_session_active_validators Active validators\n'
out += '# TYPE acala_session_active_validators counter\n'
out += '# HELP acala_activeCollators Active collators\n'
out += '# TYPE acala_activeCollators counter\n'

for k, v in metrics['validators'].items():
out += 'acala_session_active_validators{chain="%s", account="%s"} %s\n' % (chain, k, v)
for i in metrics['collators'].keys():
out += 'acala_activeCollators{chain="%s", account="%s"} 1\n' % (chain, i)
except KeyError:
pass

try:
out += '# HELP acala_rewards_validator Points earned\n'
out += '# TYPE acala_rewards_validator counter\n'
out += '# HELP acala_sessionPoints Points earned\n'
out += '# TYPE acala_sessionPoints counter\n'

for k, v in metrics['validators'].items():
out += 'acala_rewards_validator{chain="%s", account="%s"} %s\n' % (chain, k, v)
for k, v in metrics['collators'].items():
out += 'acala_sessionPoints{chain="%s", account="%s"} %s\n' % (chain, k, v)
except KeyError:
pass

Expand All @@ -61,34 +60,32 @@ def metrics():


def main():
block = 0
session = 0

while True:
try:
last_block = substrate_interface.request('System', 'Number').value
if last_block != block:
validators = substrate_interface.request('Session', 'Validators').value
current_session = substrate_interface.request('Session', 'CurrentIndex').value
current_session = substrate_interface.request('Session', 'CurrentIndex').value

result = {'validators': {}, 'common': {}}
if session != current_session:
active_collators = substrate_interface.request('Session', 'Validators').value
result = {'collators': {}, 'common': {}}

result['common'] = {}
result['common']['active_validators_count'] = len(validators)
result['common']['current_session'] = current_session

for addr in validators:
points = substrate_interface.request('CollatorSelection', 'SessionPoints', [addr]).value
validator_points = {k: points for k in validators if k == addr}
result['validators'].update(validator_points)
logging.info('New session ' + str(current_session) + ' has just begun')

q_metrics.clear()
q_metrics.append(result)
for addr in active_collators:
result['collators'][addr] = substrate_interface.request('CollatorSelection', 'SessionPoints', [addr]).value

block = last_block
q_metrics.clear()
q_metrics.append(result)

session = current_session

except Exception as e:
logging.critical(e)
time.sleep(3)
logging.critical('The main thread been stucked with error "' + str(e) + '"')
time.sleep(10)

continue

Expand Down
20 changes: 20 additions & 0 deletions exporters/astar/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM alpine/flake8:latest as linter
WORKDIR /apps/
COPY . /apps/
## ingore E501 line too long (XX > 79 characters)
RUN flake8 --ignore="E501" *.py

FROM --platform=linux/amd64 python:3.11-slim-buster

WORKDIR /

RUN apt-get update && apt-get install -y gcc g++
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt --no-cache-dir
RUN groupadd -r exporter && useradd -r -g exporter exporter

COPY --from=linter /apps/exporter.py app.py
COPY --from=linter /apps/functions.py functions.py

USER exporter
CMD ["python3", "app.py"]
131 changes: 131 additions & 0 deletions exporters/astar/exporter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#!/usr/bin/env python3
import os
import threading
import time
import logging
from collections import deque
from functions import SUBSTRATE_INTERFACE
from flask import Flask, make_response

logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=logging.INFO, datefmt='%Y-%m-%d %I:%M:%S')
app = Flask(__name__)


@app.route("/metrics")
def metrics():
metrics = q_metrics[0].copy()

out = ""

try:
out += '# HELP astar_currentSession Current session\n'
out += '# TYPE astar_currentSession counter\n'

out += 'astar_currentSession{chain="%s"} %s\n' % (chain, metrics['common']['current_session'])
except KeyError:
pass

try:
out += '# HELP astar_activeCollators Active collators\n'
out += '# TYPE astar_activeCollators counter\n'

for i in metrics['collators'].keys():
out += 'astar_activeCollators{chain="%s", account="%s"} 1\n' % (chain, i)

except KeyError:
pass

try:
out += '# HELP astar_sessionBlocks Session blocks\n'
out += '# TYPE astar_sessionBlocks counter\n'

out += 'astar_sessionBlocks{chain="%s"} %s\n' % (chain, metrics['common']['session_blocks'])
except KeyError:
pass

try:
out += '# HELP astar_blockAuthorship Blocks authored\n'
out += '# TYPE astar_blockAuthorship counter\n'

for k, v in metrics['collators'].items():
out += 'astar_blockAuthorship{chain="%s", account="%s"} %s\n' % (chain, k, v['authored_blocks_count'])
except KeyError:
pass

response = make_response(out, 200)
response.mimetype = "text/plain"

return response


def main():
block = 0
session = 0

while True:
try:
current_session = int(substrate_interface.request('Session', 'CurrentIndex').value)

if session != current_session:
active_collators = substrate_interface.request('Session', 'Validators').value
result = {'collators': {}, 'common': {}}

for addr in active_collators:
result['collators'][addr] = {'is_active': 0, 'authored_blocks_count': 0}

result['common']['current_session'] = current_session
result['common']['session_blocks'] = 0

logging.info('New session ' + str(current_session) + ' has just begun')

last_block = substrate_interface.request('System', 'Number').value

if last_block != block:
logging.info('Processing block ' + str(last_block))

for addr, params in result['collators'].items():
authored_block = substrate_interface.request('CollatorSelection', 'LastAuthoredBlock', [addr]).value

if 'last_authored_block' not in params.keys():
params['last_authored_block'] = authored_block

continue

if authored_block == last_block:
params['authored_blocks_count'] += 1
params['last_authored_block'] = authored_block

logging.info('Collator ' + str(addr) + ' has just constructed block ' + str(authored_block))

result['common']['session_blocks'] += 1

q_metrics.clear()
q_metrics.append(result)

session = current_session
block = last_block

except Exception as e:
logging.critical('The main thread been stucked with error "' + str(e) + '"')
time.sleep(10)

continue

time.sleep(3)


if __name__ == '__main__':
endpoint_listen = os.environ['LISTEN']
endpoint_port = os.environ['PORT']
ws_endpoint = os.environ['WS_ENDPOINT']
chain = os.environ['CHAIN']

substrate_interface = SUBSTRATE_INTERFACE(ws_endpoint)

q_metrics = deque([])

worker = threading.Thread(target=main)
worker.daemon = True
worker.start()

app.run(host="0.0.0.0", port=int(endpoint_port))
Loading

0 comments on commit 7308b9d

Please sign in to comment.