Skip to content

Commit

Permalink
fetch info from zilliqa network.
Browse files Browse the repository at this point in the history
  • Loading branch information
deepgully committed Feb 8, 2019
1 parent 0a31876 commit 851fe41
Show file tree
Hide file tree
Showing 11 changed files with 324 additions and 13 deletions.
3 changes: 3 additions & 0 deletions pool.conf
Expand Up @@ -36,3 +36,6 @@ smtp:
username: ""
password: ""
timeout: 1

zilliqa:
enabled: false
5 changes: 4 additions & 1 deletion zilpool/apis/eth.py
Expand Up @@ -34,7 +34,10 @@ def init_apis(config):
)

def no_work():
seconds_to_next_pow = pow.PoWWindow.seconds_to_next_pow()
if config["zilliqa"]["enabled"]:
seconds_to_next_pow = utils.Zilliqa.secs_to_next_pow()
else:
seconds_to_next_pow = pow.PoWWindow.seconds_to_next_pow()
return "", "", "", False, int(seconds_to_next_pow)

@method
Expand Down
18 changes: 14 additions & 4 deletions zilpool/apis/stats.py
Expand Up @@ -24,8 +24,7 @@

import zilpool
from zilpool.common import utils
from zilpool.pyzil import crypto
from zilpool.pyzil import ethash
from zilpool.pyzil import crypto, ethash
from zilpool.database import pow, miner, zilnode


Expand All @@ -36,7 +35,7 @@ async def stats(request):

@method
async def stats_current(request):
return current_work()
return current_work(config)

@method
@utils.args_to_lower
Expand Down Expand Up @@ -98,23 +97,34 @@ def summary():
}


def current_work():
def current_work(config):
latest_work = pow.PowWork.get_latest_work()

block_num = 0
tx_block_num = None
difficulty = [0, 0]
start_time = None

if latest_work:
block_num = latest_work.block_num
start_time = latest_work.start_time
difficulty = sorted(pow.PowWork.epoch_difficulty())

now = datetime.utcnow()
secs_next_pow = pow.PoWWindow.seconds_to_next_pow()

if config["zilliqa"]["enabled"]:
block_num = utils.Zilliqa.get_current_dsblock()
tx_block_num = utils.Zilliqa.get_current_txblock()
difficulty = utils.Zilliqa.get_difficulty()
difficulty = [ethash.difficulty_to_hashpower(d) for d in difficulty]
secs_next_pow = utils.Zilliqa.secs_to_next_pow()

next_pow_time = now + timedelta(seconds=secs_next_pow)

return {
"block_num": block_num,
"tx_block_num": tx_block_num,
"difficulty": difficulty,
"utc_time": utils.iso_format(now),
"start_time": utils.iso_format(start_time),
Expand Down
5 changes: 5 additions & 0 deletions zilpool/apis/zil.py
Expand Up @@ -47,6 +47,11 @@ async def zil_requestWork(request,
logging.warning(f"failed verify signature")
return False

if config["zilliqa"]["enabled"]:
# 0. check network info
if not utils.Zilliqa.is_pow_window():
return False

block_num = crypto.hex_str_to_int(block_num)
timeout = crypto.hex_str_to_int(timeout)

Expand Down
84 changes: 84 additions & 0 deletions zilpool/backgound.py
@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
# Zilliqa Mining Proxy
# Copyright (C) 2019 Gully Chen
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
backgound tasks
"""
import time
import logging

import asyncio
from zilpool.common import utils
from zilpool.pyzil.zilliqa_api import APIError


async def update_chain_info(config):
try:
prev_block = None
prev_time = None
latest_blocks_time = []
while True:
try:
cur_block = utils.Zilliqa.get_current_txblock()
if cur_block:
if prev_block is None:
prev_block = cur_block
prev_time = time.time()
else:
if cur_block < prev_block:
utils.Zilliqa.clear_cache()
continue

if cur_block > prev_block:
blocks = cur_block - prev_block
now = time.time()

elapsed = now - prev_time
block_time = elapsed / blocks
latest_blocks_time.append(block_time)

avg_time = sum(latest_blocks_time) / len(latest_blocks_time)
utils.Zilliqa.update_avg_block_time(avg_time)

prev_block = cur_block
prev_time = now

if len(latest_blocks_time) > 50:
latest_blocks_time = latest_blocks_time[25:]

except APIError as e:
logging.error(f"APIError {e}")

await asyncio.sleep(config["zilliqa"]["update_interval"])
except asyncio.CancelledError:
pass
except:
logging.exception("unknown error in update_chain_info")
raise
finally:
pass


async def start_background_tasks(app):
config = app["config"]
if config["zilliqa"]["enabled"]:
app["zil_background"] = app.loop.create_task(update_chain_info(config))


async def cleanup_background_tasks(app):
if "zil_background" in app:
app["zil_background"].cancel()
await app["zil_background"]
93 changes: 93 additions & 0 deletions zilpool/common/utils.py
Expand Up @@ -22,9 +22,11 @@
import hashlib
from collections import Mapping
from functools import wraps
from cachetools import TTLCache
from concurrent.futures import ThreadPoolExecutor

from zilpool.pyzil import crypto
from zilpool.pyzil import zilliqa_api

cur_dir = os.path.dirname(os.path.abspath(__file__))
app_dir = os.path.join(cur_dir, "..") # warning: take care
Expand Down Expand Up @@ -216,3 +218,94 @@ def wrapper(*args, **kwargs):
return thread_pool.submit(func, *args, **kwargs)

return wrapper


class Zilliqa:
conf = None
api = None
cache = TTLCache(maxsize=64, ttl=30)

cur_tx_block = 0
cur_ds_block = 0
shard_difficulty = 0
ds_difficulty = 0
avg_block_time = 25 # from constants.xml

@classmethod
def init(cls, conf):
cls.conf = conf["zilliqa"]
cls.api = zilliqa_api.API(cls.conf["api_endpoint"])

@classmethod
def get_cache(cls, key, func, *args, **kwargs):
val = cls.cache.get(key)
if val is None:
val = func(*args, **kwargs)
try:
cls.cache[key] = val
except KeyError:
pass
return val

@classmethod
def clear_cache(cls, key=None):
if key is None:
cls.cache.clear()
else:
cls.cache.pop(key, None)

@classmethod
def update_avg_block_time(cls, avg_time):
cls.avg_block_time = avg_time

@classmethod
def get_current_txblock(cls):
block = cls.get_cache("txblock", cls.api.GetCurrentMiniEpoch)
block = int(block or 0)
if block > cls.cur_tx_block:
cls.cur_tx_block = block

return block

@classmethod
def get_current_dsblock(cls):
block = cls.get_cache("dsblock", cls.api.GetCurrentDSEpoch)
block = int(block or 0)
if block > cls.cur_ds_block:
cls.cur_ds_block = block
return block

@classmethod
def get_difficulty(cls):
shard_difficulty = cls.get_cache("shard_difficulty",
cls.api.GetPrevDifficulty)
ds_difficulty = cls.get_cache("ds_difficulty",
cls.api.GetPrevDSDifficulty)

if shard_difficulty:
cls.shard_difficulty = shard_difficulty
if ds_difficulty:
cls.ds_difficulty = ds_difficulty
return shard_difficulty, ds_difficulty

@classmethod
def is_pow_window(cls):
if not cls.cur_tx_block:
cls.get_current_txblock()

tx_block = cls.cur_tx_block
block_per_pow = cls.conf["block_per_pow"]
block_in_epoch = tx_block % block_per_pow
return block_in_epoch in [0, block_per_pow - 1]

@classmethod
def secs_to_next_pow(cls):
if not cls.cur_tx_block:
cls.get_current_txblock()

tx_block = cls.cur_tx_block
block_per_pow = cls.conf["block_per_pow"]
block_in_epoch = tx_block % block_per_pow
if block_in_epoch == 0:
return 0 # current pow is running
return (block_per_pow - block_in_epoch) * cls.avg_block_time
6 changes: 6 additions & 0 deletions zilpool/default.conf
Expand Up @@ -48,3 +48,9 @@ smtp:
username: ""
password: ""
timeout: 1

zilliqa:
enabled: false
api_endpoint: "https://api.zilliqa.com/"
block_per_pow: 100
update_interval: 30 # in seconds
10 changes: 10 additions & 0 deletions zilpool/poolserver.py
Expand Up @@ -28,6 +28,8 @@
from jsonrpcserver import async_dispatch
from jsonrpcserver.response import ExceptionResponse

from zilpool import backgound


# setup root logger
FORMATTER = logging.Formatter(
Expand Down Expand Up @@ -138,11 +140,19 @@ def start_servers(conf_file=None, host=None, port=None):
connect_to_db(config)
init_db(config)

# init Zilliqa network APIs
utils.Zilliqa.init(config)

# init app
app = web.Application(debug=config["debug"])
init_apis(app, config)
init_website(app, config)

# start background tasks
app["config"] = config
app.on_startup.append(backgound.start_background_tasks)
app.on_cleanup.append(backgound.cleanup_background_tasks)

# start the server
if port is None:
port = config["api_server"].get("port", "4202")
Expand Down

0 comments on commit 851fe41

Please sign in to comment.