This commit is contained in:
Marco van Dijk 2022-12-27 17:02:53 +01:00
parent 5b426dc22c
commit bc2097709d
5 changed files with 128 additions and 258 deletions

30
.gitignore vendored
View File

@ -1,30 +0,0 @@
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# Support for Project snippet scope
.vscode/*.code-snippets
# Ignore code-workspaces
*.code-workspace
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode

View File

@ -1,3 +0,0 @@
{
"python.formatting.provider": "autopep8"
}

105
README.md
View File

@ -1,88 +1,31 @@
# better call reward
## better call reward
#### Script to call `reward` for Livepeer orchestrator.
This script uses a list of configured URL's Orchestrator CLI URL's to get info on the last reward call round and current Livepeer round
Then compare these numbers and if they are not the same calls `reward`.
What this do?
This script uses livepeer API to get info on the last reward call round and current round.
Then compare these numbers and if they are not the same just call to `reward`.
Script in default is checking numbers every 1h. You can change this value by editing `retryTimeReward`
Modify the `ORCH_TARGETS` variable in `RewardCall.py` to set your Orchestrator URL's
My Orchestrator has many missing `reward` calls and this was the main motivation to create this script.
### Dependencies
#### help:
Requires python 3 and pip: `sudo pacman -S python python-pip`
Then install the requests library using pip `python -m pip install requests`
### Running the script
Recommended to run `better-call-reward.py` as a systemd service:
Move the script to an accessible location, like `/usr/local/bin`
`sudo nano /etc/systemd/system/rewardCaller.service`
```
usage: better-call-reward.py [-h] [-url [URL]] [-delay [DELAY]]
[Unit]
Description=Reward Caller
After=multi-user.target
Optional app description
optional arguments:
-h, --help show this help message and exit
-url [URL] URL for your Orchestrator
```
#### example usage:
`./better-call-reward.py -url http://localhost:7935`
`./better-call-reward.py ` - this use default url `http://localhost:7935`
#### script output on succes:
```
Orchestrator URL: http://192.168.137.103:7935
Connection success
---Info---
Orchestrator Version: 0.5.31-ec920c67
GolangRuntimeVersion: go1.18.1
Transcoders:
[1] Address: 127.0.0.1:54396 Capacity:14
[ 2022-06-02 10:40:36.105142 ] Orchestrator status: online
[ 2022-06-02 10:40:36.105176 ] Last reward round: 2584
[ 2022-06-02 10:40:36.105190 ] Current round: 2585
[ 2022-06-02 10:40:36.105195 ] Call to reward!
[ 2022-06-02 10:42:32.865710 ] <Response [200]>
[ 2022-06-02 10:42:32.865755 ] Call reward success.
. Next call: 3534s
```
#### example output from O:
```
I0602 10:40:35.750595 417331 handlers.go:845] Calling reward
2022/06/02 10:41:30 http: TLS handshake error from 208.115.199.25:41434: EOF
I0602 10:42:31.336083 417331 transactionManager.go:119]
******************************Eth Transaction******************************
Invoking transaction: "rewardWithHint". Inputs: "_newPosPrev: 0x86c5A8231712CC8aaa23409B5ad315f304C09531 _newPosNext: 0x22Ae24C2D1f489906266609d14c4C0387909A38a" Hash: "0x410696c59c24527e9c34323be46470f96694cc870982d674ea1b222ae25c59b5".
***************************************************************************
I0602 10:42:32.508922 417331 handlers.go:855] Call to reward successful
```
#### some error:
```
Orchestrator URL: http://192.168.137.103:7935
Connection success
---Info---
Orchestrator Version: 0.5.31-ec920c67
GolangRuntimeVersion: go1.18.1
Transcoders:
[1] Address: 127.0.0.1:54396 Capacity:14
[ 2022-06-02 10:33:26.291112 ] Orchestrator status: online
[ 2022-06-02 10:33:26.291156 ] Last reward round: 2584
[ 2022-06-02 10:33:26.291175 ] Current round: 2585
[ 2022-06-02 10:33:26.291189 ] Call to reward!
[ 2022-06-02 10:33:26.292445 ] <Response [404]>
[ 2022-06-02 10:33:26.292469 ] Call to reward fail. Error: <Response [404]>
```
Buy me a coffee: <br />
LPT (Arbitrum): `0xE32971e1a55152A94Fa55DFb80ACdC4bA55679C3` <br />
AETH (Arbitrum): `0xE32971e1a55152A94Fa55DFb80ACdC4bA55679C3` <br />
ETH: `0xE32971e1a55152A94Fa55DFb80ACdC4bA55679C3` <br />
DOGE: `D8mJBFdSQscQKce2vnPsKr4dC4sFvypBfU` <br />
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/python3 /usr/local/bin/RewardCall.py
[Install]
WantedBy=multi-user.target
```

104
RewardCall.py Executable file
View File

@ -0,0 +1,104 @@
#!/bin/python3
import requests
import time
import sys
from datetime import datetime
# EDIT THIS to set your O cliAddr targets which this script should call reward on
ORCH_TARGETS = ['http://127.0.0.1:7935']
# Global Constants
sleepTimeActive = 60 # Wait time when there is any O which has to call reward this round
sleepTimeIdle = 60 * 60 * 4 # Wait time between round checks
# Logs `info` to the terminal with an attached datetime
def log(info):
print("[", datetime.now(), "] - ", info)
sys.stdout.flush()
# Gets the last round the orch called reward
def getLastRewardRound(url):
try:
r = requests.get(url + '/orchestratorInfo')
except requests.exceptions.RequestException as e:
return 0
if r.status_code != 200:
return 0
return r.json()['Transcoder']['LastRewardRound']
# Return the current active Livepeer round
def getCurrentRound(url):
try:
r = requests.get(url + '/currentRound')
except requests.exceptions.RequestException as e:
return 0
if r.status_code != 200:
return 0
return int(r.content.hex(), 16)
class Orchestrator:
def __init__(self, uri):
self.uri = uri
self.rewardRound = 0
self.currentRound = 0
self.hasReward = False
latestRound = 0
orchestrators = []
# Init orch objecs
for url in ORCH_TARGETS:
log("Adding Orchestrator with URL '" + url + "'")
orchestrators.append(Orchestrator(url))
# Main loop
while True:
# Init delay to a long sleep time. Override later if an O requires reward calling
delay = sleepTimeIdle
for i in range(len(orchestrators)):
# Update last round if we have a new one
currentRound = getCurrentRound(orchestrators[i].uri)
if currentRound == 0:
log("Error: can't get current round info on '" + url + "'")
orchestrators[i].hasReward = False
delay = sleepTimeActive
continue
if currentRound > latestRound:
latestRound = currentRound
# Reset hasReward flags for all O's since the latest round has changed
for j in range(len(orchestrators)):
orchestrators[j].hasReward = False
# If we are behind in rounds, notify user
if currentRound < latestRound:
log("Orchestrator '" + orchestrators[i].uri + "' is behind in block syncing!")
# We can continue now if the latest round has not changed
if orchestrators[i].hasReward:
log("Skipping Orchestrator '" + orchestrators[i].uri + "' since they have called reward this round")
continue
# Check the last reward round
lastRewardRound = getLastRewardRound(orchestrators[i].uri)
if lastRewardRound == 0:
log("Error: can't get last reward round info on '" + url + "'")
orchestrators[i].hasReward = False
delay = sleepTimeActive
continue
log("Latest reward round for Orchestrator '" + orchestrators[i].uri + "' is " + str(lastRewardRound) + " and the latest livepeer round is " + str(latestRound))
if lastRewardRound < latestRound:
log("Calling reward for '" + orchestrators[i].uri + "'")
r = requests.get(orchestrators[i].uri + '/reward')
log(r)
if r.status_code == 200:
log('Call to reward success.')
orchestrators[i].hasReward = True
else:
log('Call to reward fail. Error: ' + str(r))
orchestrators[i].hasReward = False
delay = sleepTimeActive
else:
orchestrators[i].hasReward = True
log("Orchestrator '" + orchestrators[i].uri + "' has already called reward in round " + str(latestRound))
# Sleep a long or short time based on whether all Orchestrators have been handled
while delay > 0:
log("Next check in " + str(delay) + " seconds...")
delay = delay - 30
time.sleep(30)

View File

@ -1,144 +0,0 @@
#!/bin/python3
from asyncio import constants
from pyclbr import Function
import requests
import time
import sys
import argparse
from datetime import datetime
# set your Orchestrator url
URL_DEFAULT = 'http://localhost:7935' # default
retryTimeOffline = 60 # delay when O is offline, in seconds
retryTimeReward = 60 * 60 # time retry call "reward ", in seconds
def parseArgs():
# Instantiate the parser
parser = argparse.ArgumentParser(
description='Script to resolve problem with livepeer "reward" call. ')
parser.add_argument('-url', type=str, nargs='?',
help='URL for your Orchestrator')
# todo: ? add delay params
# parser.add_argument('-delay', type=int, nargs='?',
# help='delay between next try of call "reward"')
# Parse the argument
args = parser.parse_args()
if args.url is None:
url = URL_DEFAULT
else:
url = args.url
print("Orchestrator URL: " + url)
return url
# end parseArgs()
def statusOrch(url): # /status , check O status and get some info
try:
r = requests.get(url + '/status')
responseStatus = r.status_code
except requests.exceptions.RequestException as e: # This is the correct syntax
print("Error during connection to '" + url +
"'. Please check your Orchestrator url.")
exit(0)
print("Connection success")
print("---Info---")
print("Orchestrator Version: " + r.json()['Version'])
print("GolangRuntimeVersion: " + r.json()['GolangRuntimeVersion'])
print("")
# transcoders info
print("Transcoders:")
i = 1
for t in r.json()['RegisteredTranscoders']:
print("["+str(i) + "] Address: " + t['Address'] +
" Capacity:" + str(t['Capacity']))
# end statusOrch(url) ----------------------------------------------
def pingOrch(url): # /status
try:
requests.get(url + '/status')
except requests.exceptions.RequestException as e: # This is the correct syntax
print("Error during connection to '" + url +
"'. Please check your Orchestrator url.")
return False
return True
# end pingOrch() ----------------------------------------------
def getLastRewardRound(url): # /orchestratorInfo
try:
r = requests.get(url + '/orchestratorInfo')
except requests.exceptions.RequestException as e: # This is the correct syntax
print("Error: can't get 'Last Reward Round' round info.")
return -1
if r.status_code != 200:
print("Can not get last reward round info. Error: " + str(r))
return -2
return r.json()['Transcoder']['LastRewardRound']
# end getLastRewardRound() ----------------------------------------------
def getCurrentRound(url): # /currentRound
# get current Round value
try:
r = requests.get(url + '/currentRound')
except requests.exceptions.RequestException as e: # This is the correct syntax
print("Error: can't get 'current Round' info.")
return -1
if r.status_code != 200:
print("Error: can't get 'current Round' info."+" ERROR: " + str(r))
return -2
currentRound = int(r.content.hex(), 16)
return currentRound
# end getLastRewardRound() ----------------------------------------------
def log(info):
print("[", datetime.now(), "]", info)
# end log(info) ----------------------------------------------
url = parseArgs()
statusOrch(url)
print("")
while True:
lastRewardRound = getLastRewardRound(url)
currentRound = getCurrentRound(url)
log('Orchestrator status: ' + ('online' if pingOrch(url) else 'offline'))
if (currentRound < 0 or lastRewardRound < 0):
log("Is Orchestrator online ?")
delay = retryTimeOffline
else:
log('Last reward round: ' + str(lastRewardRound))
log('Current round: ' + str(currentRound))
if currentRound != lastRewardRound:
log('Call reward!')
r = requests.get(url + '/reward') # call reward
log(r)
if r.status_code == 200:
log('Call to reward success.')
else:
log('Call to reward fail. Error: ' + str(r))
else:
log('Do not call reward. ' + 'Reward for current round ' +
str(currentRound) + ' already called.')
delay = retryTimeReward
while delay > 0:
print(". Next call: " + str(delay) + "s " + "\r", end="")
sys.stdout.flush()
delay = delay - 1
time.sleep(1)
print(" ")
sys.stdout.flush()
print("----------------------------")