diff --git a/.flake8 b/.flake8
new file mode 100644
index 000000000..93814ad02
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,3 @@
+[flake8]
+max-line-length = 100
+exclude = .git,__pycache__,docs/source/conf.py,old,build,dist,venv,node_modules
\ No newline at end of file
diff --git a/VERSION b/VERSION
index 79a2734bb..09a3acfa1 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.5.0
\ No newline at end of file
+0.6.0
\ No newline at end of file
diff --git a/app.py b/app.py
index 0eac8f037..1a29e777f 100644
--- a/app.py
+++ b/app.py
@@ -17,30 +17,27 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-import os
import logging
from flask import Flask, render_template, session, g
from peewee import SqliteDatabase
-import sentry_sdk
-
from skale import Skale
from skale.wallets import RPCWallet
from core.node import Node
-from core.local_wallet import LocalWallet
+from core.node_config import NodeConfig
+from core.schains.monitor import SchainsMonitor
+from core.schains.cleaner import SChainsCleaner
-from tools.helper import get_sentry_env_name
-from tools.configs import NODE_CONFIG_FILEPATH, FLASK_SECRET_KEY_FILE
-from tools.configs.web3 import ENDPOINT, ABI_FILEPATH
+from tools.configs import FLASK_SECRET_KEY_FILE
+from tools.configs.web3 import ENDPOINT, ABI_FILEPATH, TM_URL
from tools.configs.db import DB_FILE
from tools.logger import init_admin_logger
-from tools.config_storage import ConfigStorage
-from tools.token_utils import TokenUtils
from tools.docker_utils import DockerUtils
from tools.str_formatters import arguments_list_string
-from tools.sgx_utils import generate_sgx_key
+from tools.sgx_utils import generate_sgx_key, sgx_server_text
+from tools.token_utils import init_user_token
from tools.configs.flask import FLASK_APP_HOST, FLASK_APP_PORT, FLASK_DEBUG_MODE
from web.user import User
@@ -61,39 +58,31 @@
werkzeug_logger = logging.getLogger('werkzeug') # todo: remove
werkzeug_logger.setLevel(logging.WARNING) # todo: remove
-rpc_wallet = RPCWallet(os.environ['TM_URL'])
+rpc_wallet = RPCWallet(TM_URL)
skale = Skale(ENDPOINT, ABI_FILEPATH, rpc_wallet)
-wallet = LocalWallet(skale, rpc_wallet)
-config = ConfigStorage(NODE_CONFIG_FILEPATH)
+
docker_utils = DockerUtils()
-node = Node(skale, config, wallet)
-token_utils = TokenUtils()
user_session = UserSession(session)
-SENTRY_URL = os.environ.get('SENTRY_URL', None)
-if SENTRY_URL:
- sentry_env_name = get_sentry_env_name(skale.manager.address)
- sentry_sdk.init(SENTRY_URL, environment=sentry_env_name)
-
-
-if not token_utils.get_token():
- token_utils.add_token()
-token = token_utils.get_token()
+node_config = NodeConfig()
+node = Node(skale, node_config)
+schains_monitor = SchainsMonitor(skale, node_config)
+schains_cleaner = SChainsCleaner(skale, node_config)
+token = init_user_token()
database = SqliteDatabase(DB_FILE)
app = Flask(__name__)
app.register_blueprint(construct_auth_bp(user_session, token))
app.register_blueprint(web_logs)
app.register_blueprint(construct_nodes_bp(skale, node, docker_utils))
-app.register_blueprint(construct_schains_bp(skale, wallet, docker_utils, node))
-app.register_blueprint(construct_wallet_bp(wallet))
-app.register_blueprint(construct_node_info_bp(skale, wallet, docker_utils))
+app.register_blueprint(construct_schains_bp(skale, node_config, docker_utils))
+app.register_blueprint(construct_wallet_bp(skale))
+app.register_blueprint(construct_node_info_bp(skale, docker_utils))
app.register_blueprint(construct_security_bp())
-app.register_blueprint(construct_validators_bp(skale, config, wallet))
-app.register_blueprint(construct_metrics_bp(skale, config))
+app.register_blueprint(construct_validators_bp(skale, node_config))
+app.register_blueprint(construct_metrics_bp(skale, node_config))
-wallet.get_or_generate()
@app.before_request
def before_request():
@@ -113,9 +102,13 @@ def main():
if __name__ == '__main__':
- logger.info(arguments_list_string({'Root account token': token}, 'Starting Flask server'))
+ logger.info(arguments_list_string({
+ 'Endpoint': ENDPOINT,
+ 'Transaction manager': TM_URL,
+ 'SGX Server': sgx_server_text()
+ }, 'Starting Flask server'))
if not User.table_exists():
User.create_table()
- generate_sgx_key(config)
+ generate_sgx_key(node_config)
app.secret_key = FLASK_SECRET_KEY_FILE
app.run(debug=FLASK_DEBUG_MODE, port=FLASK_APP_PORT, host=FLASK_APP_HOST, use_reloader=False)
diff --git a/core/local_wallet.py b/core/local_wallet.py
deleted file mode 100644
index f170ae383..000000000
--- a/core/local_wallet.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of SKALE Admin
-#
-# Copyright (C) 2019 SKALE Labs
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero 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 Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import logging
-from tools.configs import LOCAL_WALLET_FILEPATH
-from tools.config_storage import ConfigStorage
-
-logger = logging.getLogger(__name__)
-
-# todo: move to smart contracts
-DEPOSIT_AMOUNT_SKL = 100
-DEPOSIT_AMOUNT_ETH = 0.2
-
-DEPOSIT_AMOUNT_SKL_WEI = DEPOSIT_AMOUNT_SKL * (10 ** 18)
-DEPOSIT_AMOUNT_ETH_WEI = int(DEPOSIT_AMOUNT_ETH * (10 ** 18))
-
-class LocalWallet: # todo: refactor
- def __init__(self, skale, wallet):
- self.skale = skale
- self.wallet = wallet
- #self.skale.web3.eth.enable_unaudited_features() # todo: deal with this
-
- def generate_local_wallet(self, password=None, extra_entropy=''):
- return {'address': self.wallet.address}
-
- def get_or_generate(self):
- return self.generate_local_wallet()
-
- def get_full(self):
- local_wallet_config = ConfigStorage(LOCAL_WALLET_FILEPATH)
- return local_wallet_config.get()
-
- def get(self):
- return self.generate_local_wallet()
-
- def get_with_balance(self):
- wallet = self.get()
- if not wallet.get('address', None):
- return wallet
-
- eth_balance_wei = self.skale.web3.eth.getBalance(wallet['address'])
- skale_balance_wei = self.skale.token.get_balance(wallet['address'])
-
- logging.debug(f'get_with_balance raw info: address: {wallet["address"]}, eth_balance_wei: {eth_balance_wei}, skale_balance_wei: {skale_balance_wei}')
-
- wallet['eth_balance_wei'] = str(eth_balance_wei)
- wallet['skale_balance_wei'] = str(skale_balance_wei)
- wallet['eth_balance'] = str(self.skale.web3.fromWei(eth_balance_wei, 'ether'))
- wallet['skale_balance'] = str(self.skale.web3.fromWei(skale_balance_wei, 'ether'))
-
- return wallet
-
- def check_required_balance(self):
- wallet = self.get_with_balance()
- return int(wallet['eth_balance_wei']) >= DEPOSIT_AMOUNT_ETH_WEI and int(wallet[
- 'skale_balance_wei']) >= DEPOSIT_AMOUNT_SKL_WEI
-
- def get_required_balance(self):
- return {'eth_balance': DEPOSIT_AMOUNT_ETH, 'skale_balance': DEPOSIT_AMOUNT_SKL}
diff --git a/core/node.py b/core/node.py
new file mode 100644
index 000000000..2ffb35308
--- /dev/null
+++ b/core/node.py
@@ -0,0 +1,111 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of SKALE Admin
+#
+# Copyright (C) 2019 SKALE Labs
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import logging
+from enum import Enum
+import docker
+
+from core.filebeat import run_filebeat_service
+
+from tools.str_formatters import arguments_list_string
+from tools.wallet_utils import check_required_balance
+
+from skale.utils.web3_utils import wait_receipt, check_receipt
+from skale.utils.helper import ip_from_bytes
+from skale.wallets.web3_wallet import public_key_to_address
+
+docker_client = docker.from_env()
+logger = logging.getLogger(__name__)
+
+
+class NodeStatuses(Enum):
+ """This class contains possible node statuses"""
+ NOT_CREATED = 0
+ REQUESTED = 1
+ CREATED = 2
+ ERROR = 3
+
+
+class Node:
+ """This class contains node registration logic"""
+ def __init__(self, skale, config):
+ self.skale = skale
+ self.config = config
+
+ def register(self, ip, public_ip, port, name):
+ """
+ Main node registration function.
+
+ Parameters:
+ ip (str): P2P IP address that will be assigned to the node
+ public_ip (str): Public IP address that will be assigned to the node
+ port (int): Base port that will be used for sChains on the node
+ name (str): Node name
+
+ Returns:
+ dict: Execution status and node config
+ """
+ self._log_node_info('Node create started', ip, public_ip, port, name)
+ if self.config.id is not None:
+ return self._node_already_exist()
+ if not check_required_balance(self.skale):
+ return self._insufficient_funds()
+ res = self.skale.manager.create_node(ip, int(port), name, public_ip)
+ receipt = wait_receipt(self.skale.web3, res['tx'])
+ try:
+ check_receipt(receipt)
+ except ValueError as err:
+ logger.error(arguments_list_string({'tx': res['tx']}, 'Node creation failed', 'error'))
+ return {'status': 0, 'errors': [err]}
+ self._log_node_info('Node successfully created', ip, public_ip, port, name)
+ res = self.skale.nodes_data.node_name_to_index(name)
+ self.config.id = self.skale.nodes_data.node_name_to_index(name)
+ # run_filebeat_service(public_ip, self.config.id, self.skale) # todo: uncomment!
+ return {'status': 1, 'data': self.config.all()}
+
+ def _insufficient_funds(self):
+ err_msg = f'Insufficient funds, re-check your wallet'
+ logger.error(err_msg)
+ return {'status': 0, 'errors': [err_msg]}
+
+ def _node_already_exist(self):
+ err_msg = f'Node is already installed on this machine. Node ID: {self.config.id}'
+ logger.error(err_msg)
+ return {'status': 0, 'errors': [err_msg]}
+
+ def _log_node_info(self, title, ip, public_ip, port, name):
+ log_params = {'IP': ip, 'Public IP': public_ip, 'Port': port, 'Name': name}
+ logger.info(arguments_list_string(log_params, title))
+
+ @property
+ def info(self):
+ _id = self.config.id
+ if _id is not None:
+ raw_info = self.skale.nodes_data.get(_id)
+ return self._transform_node_info(raw_info, _id)
+ return {'status': NodeStatuses.NOT_CREATED.value}
+
+ def _transform_node_info(self, node_info, node_id):
+ node_info['ip'] = ip_from_bytes(node_info['ip'])
+ node_info['publicIP'] = ip_from_bytes(node_info['publicIP'])
+ node_info['status'] = NodeStatuses.CREATED.value
+ node_info['id'] = node_id
+ node_info['publicKey'] = self.skale.web3.toHex(node_info['publicKey'])
+ node_info['owner'] = public_key_to_address(node_info['publicKey'])
+ return node_info
diff --git a/core/node/__init__.py b/core/node/__init__.py
deleted file mode 100644
index f30227df3..000000000
--- a/core/node/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from core.node.main import Node
\ No newline at end of file
diff --git a/core/node/main.py b/core/node/main.py
deleted file mode 100644
index 6469fba0b..000000000
--- a/core/node/main.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of SKALE Admin
-#
-# Copyright (C) 2019 SKALE Labs
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero 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 Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import docker, logging
-
-from core.schains.monitor import SchainsMonitor
-from core.schains.cleaner import SChainsCleaner
-from core.node.statuses import NodeStatuses
-from core.filebeat import run_filebeat_service
-
-from tools.str_formatters import arguments_list_string
-
-import skale.utils.helper as Helper
-
-docker_client = docker.from_env()
-logger = logging.getLogger(__name__)
-
-
-class Node:
- def __init__(self, skale, config, wallet):
- self.skale = skale
- self.wallet = wallet
- self.config = config
-
- node_id = self.get_node_id()
- if node_id is not None:
- self.run_schains_monitor(node_id)
-
- self.install_nonce = None
- self.install_address = None
-
- def run_schains_monitor(self, node_id):
- self.schains_monitor = SchainsMonitor(self.skale, self.wallet, node_id)
- self.schains_cleaner = SChainsCleaner(self.skale, node_id)
-
- def create(self, ip, public_ip, port, name):
- log_params = {'IP': ip, 'Public IP': public_ip, 'Port': port, 'Name': name}
- logger.info(arguments_list_string(log_params, 'Node create started'))
-
- node_id = self.get_node_id()
- if node_id:
- err_msg = f'Node is already installed on this machine. Node ID: {node_id}'
- logger.error(err_msg)
- return {'status': 0, 'errors': [err_msg]}
-
- if not self.wallet.check_required_balance():
- wallet = self.wallet.get_with_balance()
- required_balances = self.wallet.get_required_balance()
- err_msg = f'Balance is too low to create a node: {wallet["eth_balance"]} ETH, {wallet["skale_balance"]} SKALE'
- required_balance_msg = f'Required amount: {required_balances["eth_balance"]} ETH, {required_balances["skale_balance"]} SKALE'
- logger.error(err_msg)
- logger.error(required_balance_msg)
- return {'status': 0, 'errors': [err_msg, required_balance_msg]}
-
- local_wallet = self.wallet.get()
- res = self.skale.manager.create_node(ip, int(port), name, public_ip)
- logger.info(f'create_node res: {res}')
-
- self.install_nonce = res['nonce']
- self.install_address = local_wallet['address']
- receipt = Helper.await_receipt(self.skale.web3, res[
- 'tx']) # todo: return tx and wait for the receipt in async mode
-
-
- if receipt['status'] != 1:
- err_msg = f'Transaction failed. TX: {res["tx"]}' # todo: convert to hex
- logger.error(arguments_list_string({'tx': res["tx"]}, 'Node creation failed', 'error'))
- logger.error(f'create_node receipt: {receipt}')
- return {'status': 0, 'errors': [err_msg]}
-
- logger.info(arguments_list_string(log_params, 'Node successfully created', 'success'))
-
- node_id = self.skale.nodes_data.node_name_to_index(name)
- self.config.update({'node_id': node_id})
- self.run_schains_monitor(node_id)
- run_filebeat_service(public_ip, node_id, self.skale)
- return {'status': 1, 'data': self.config.get()}
-
- def get_node_id(self):
- try:
- return self.config['node_id']
- except KeyError:
- logger.debug('get_node_id: No node installed on this machine.')
- return None
-
- def get_node_info(self):
- node_id = self.get_node_id()
- if node_id is not None:
- node_info = self.skale.nodes_data.get(node_id)
- if not node_info: return {'status': NodeStatuses.ERROR.value}
- return self.transform_node_info(node_info, node_id)
- else:
- return {'status': NodeStatuses.NOT_CREATED.value}
-
- def transform_node_info(self, node_info, node_id):
- node_info['ip'] = Helper.ip_from_bytes(node_info['ip'])
- node_info['publicIP'] = Helper.ip_from_bytes(node_info['publicIP'])
- node_info['status'] = NodeStatuses.CREATED.value
- node_info['id'] = node_id
- node_info['publicKey'] = self.skale.web3.toHex(node_info['publicKey'])
- node_info['owner'] = Helper.public_key_to_address(node_info['publicKey'])
- return node_info
\ No newline at end of file
diff --git a/core/node/statuses.py b/core/node/statuses.py
deleted file mode 100644
index 179685396..000000000
--- a/core/node/statuses.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of SKALE Admin
-#
-# Copyright (C) 2019 SKALE Labs
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero 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 Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-from enum import Enum
-
-
-class NodeStatuses(Enum):
- NOT_CREATED = 0
- REQUESTED = 1
- CREATED = 2
- ERROR = 3
-
- # def __str__(self):
- # return str(self.value)
diff --git a/core/node/utils.py b/core/node/utils.py
deleted file mode 100644
index 10a9e1be8..000000000
--- a/core/node/utils.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of SKALE Admin
-#
-# Copyright (C) 2019 SKALE Labs
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero 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 Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import logging
-
-logger = logging.getLogger(__name__)
-
-
-def get_node_id(config):
- try:
- return config['node_id']
- except KeyError:
- logger.info('get_node_id: No node installed on this machine.')
- return None
diff --git a/core/node_config.py b/core/node_config.py
new file mode 100644
index 000000000..0a0fccb0c
--- /dev/null
+++ b/core/node_config.py
@@ -0,0 +1,57 @@
+import functools
+from filelock import FileLock
+
+from tools.helper import read_json, write_json, init_file
+from tools.configs import NODE_CONFIG_FILEPATH
+
+
+LOCK_PATH = '/tmp/skale_node_config.lock'
+
+
+def config_setter(func):
+ @functools.wraps(func)
+ def wrapper_decorator(*args, **kwargs):
+ field_name, field_value = func(*args, **kwargs)
+ lock = FileLock(LOCK_PATH)
+ with lock:
+ config = read_json(NODE_CONFIG_FILEPATH)
+ config[field_name] = field_value
+ write_json(NODE_CONFIG_FILEPATH, config)
+ return wrapper_decorator
+
+
+def config_getter(func):
+ @functools.wraps(func)
+ def wrapper_decorator(*args, **kwargs):
+ field_name = func(*args, **kwargs)
+ config = read_json(NODE_CONFIG_FILEPATH)
+ return config.get(field_name)
+ return wrapper_decorator
+
+
+class NodeConfig():
+ def __init__(self):
+ init_file(NODE_CONFIG_FILEPATH, {})
+
+ @property
+ @config_getter
+ def id(self) -> int:
+ return 'node_id'
+
+ @id.setter
+ @config_setter
+ def id(self, node_id: int) -> None:
+ return 'node_id', node_id
+
+ @property
+ @config_getter
+ def sgx_key_name(self) -> int:
+ return 'sgx_key_name'
+
+ @sgx_key_name.setter
+ @config_setter
+ def sgx_key_name(self, sgx_key_name: int) -> None:
+ return 'sgx_key_name', sgx_key_name
+
+ def all(self) -> dict:
+ return read_json(NODE_CONFIG_FILEPATH)
diff --git a/core/schains/__init__.py b/core/schains/__init__.py
index 6cd8d0404..97a4ec847 100644
--- a/core/schains/__init__.py
+++ b/core/schains/__init__.py
@@ -1,3 +1,21 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of SKALE Admin
+#
+# Copyright (C) 2019 SKALE Labs
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
MONITOR_INTERVAL = 10
-CLEANER_INTERVAL = 60
\ No newline at end of file
+CLEANER_INTERVAL = 60
diff --git a/core/schains/checks.py b/core/schains/checks.py
index 3a5f1919a..606e895ac 100644
--- a/core/schains/checks.py
+++ b/core/schains/checks.py
@@ -103,5 +103,8 @@ def log_health_check(self):
failed_checks_str = ", ".join(failed_checks)
logger.info(
- arguments_list_string({'sChain name': self.name, 'Failed checks': failed_checks_str},
- 'Failed sChain checks', 'error'))
+ arguments_list_string(
+ {'sChain name': self.name, 'Failed checks': failed_checks_str},
+ 'Failed sChain checks', 'error'
+ )
+ )
diff --git a/core/schains/cleaner.py b/core/schains/cleaner.py
index 764b8fd10..d3756abc5 100644
--- a/core/schains/cleaner.py
+++ b/core/schains/cleaner.py
@@ -20,27 +20,41 @@
import os
import logging
import shutil
+from time import sleep
+
+from skale import Skale
from core.schains.checks import SChainChecks
from core.schains.helper import get_schain_dir_path
+from core.schains.runner import get_container_name
+
from tools.docker_utils import DockerUtils
-from tools.configs.schains import SCHAINS_DIR_PATH
from tools.custom_thread import CustomThread
from tools.str_formatters import arguments_list_string
-from . import CLEANER_INTERVAL
-
-from core.schains.runner import get_container_name
+from tools.configs.web3 import ENDPOINT, ABI_FILEPATH
+from tools.configs.schains import SCHAINS_DIR_PATH
from tools.configs.containers import SCHAIN_CONTAINER, IMA_CONTAINER
+from . import CLEANER_INTERVAL, MONITOR_INTERVAL
+
+
logger = logging.getLogger(__name__)
dutils = DockerUtils()
class SChainsCleaner():
- def __init__(self, skale, node_id):
+ def __init__(self, skale, node_config):
self.skale = skale
- self.node_id = node_id
+ self.node_config = node_config
+ self.skale_events = Skale(ENDPOINT, ABI_FILEPATH)
+ CustomThread('Wait for node ID', self.wait_for_node_id, once=True).start()
+
+ def wait_for_node_id(self, opts):
+ while self.node_config.id is None:
+ logger.debug('Waiting for the node_id in sChains Cleaner...')
+ sleep(MONITOR_INTERVAL)
+ self.node_id = self.node_config.id
self.monitor = CustomThread('sChains cleaner monitor', self.schains_cleaner,
interval=CLEANER_INTERVAL)
self.monitor.start()
@@ -49,7 +63,7 @@ def schains_cleaner(self, opts):
schains_on_node = self.get_schains_on_node()
schain_ids = self.schain_names_to_ids(schains_on_node)
- event_filter = self.skale.schains.contract.events.SchainDeleted.createFilter(
+ event_filter = self.skale_events.schains.contract.events.SchainDeleted.createFilter(
fromBlock=0, argument_filters={'schainId': schain_ids})
events = event_filter.get_all_entries()
diff --git a/core/schains/config.py b/core/schains/config.py
index 2eae23909..8a03967b1 100644
--- a/core/schains/config.py
+++ b/core/schains/config.py
@@ -32,7 +32,7 @@
logger = logging.getLogger(__name__)
-def generate_schain_config(schain_name, node_id, skale):
+def generate_schain_config(schain_name, schain_owner, node_id, skale):
node_info = skale.schains_data.get_current_node_for_schain_config(schain_name, node_id)
schain_struct = skale.schains_data.get_by_name(schain_name)
@@ -43,6 +43,7 @@ def generate_schain_config(schain_name, node_id, skale):
"sChain": {
"schainID": 1, # todo!
"schainName": schain_name,
+ "schainOwner": schain_owner,
"nodes": schain_nodes
}
}
@@ -77,6 +78,7 @@ def generate_allocation(schain, schain_nodes):
schain['name']))
return allocation
+
def add_chain_id(base_config, schain_name):
keccak_hash = keccak.new(digest_bits=256)
keccak_hash.update(schain_name.encode("utf-8"))
@@ -84,6 +86,7 @@ def add_chain_id(base_config, schain_name):
hash = hash[:13] # use 52 bits
base_config['params']['chainID'] = "0x" + hash
+
def save_schain_config(schain_config, schain_name):
schain_config_filepath = get_schain_config_filepath(schain_name)
with open(schain_config_filepath, 'w') as outfile:
diff --git a/core/schains/monitor.py b/core/schains/monitor.py
index 409e070d2..d0163de6b 100644
--- a/core/schains/monitor.py
+++ b/core/schains/monitor.py
@@ -19,16 +19,16 @@
import os
import logging
+from time import sleep
+
from tools.custom_thread import CustomThread
from tools.docker_utils import DockerUtils
from tools.str_formatters import arguments_list_string
-from sentry_sdk import capture_message
-
from core.schains.runner import run_schain_container, run_ima_container
from core.schains.helper import init_schain_dir, get_schain_config_filepath
from core.schains.config import generate_schain_config, save_schain_config, get_schain_env
-from core.schains.volume import init_data_volume, get_container_limits
+from core.schains.volume import init_data_volume
from core.schains.checks import SChainChecks
from core.schains.ima import get_ima_env
from core.schains.dkg import init_bls, FailedDKG
@@ -43,24 +43,31 @@
class SchainsMonitor():
- def __init__(self, skale, wallet, node_id):
+ def __init__(self, skale, node_config):
self.skale = skale
- self.node_id = node_id
- self.wallet = wallet
+ self.node_config = node_config
+ CustomThread('Wait for node ID', self.wait_for_node_id, once=True).start()
+
+ def wait_for_node_id(self, opts):
+ while self.node_config.id is None:
+ logger.debug('Waiting for the node_id in sChains Monitor...')
+ sleep(MONITOR_INTERVAL)
+ self.node_id = self.node_config.id
self.monitor = CustomThread('sChains monitor', self.monitor_schains,
interval=MONITOR_INTERVAL)
self.monitor.start()
def monitor_schains(self, opts):
schains = self.skale.schains_data.get_schains_for_node(self.node_id)
- schains_on_node = sum(map(lambda schain: schain['active'] == True, schains))
+ schains_on_node = sum(map(lambda schain: schain['active'], schains))
schains_holes = len(schains) - schains_on_node
logger.info(
arguments_list_string({'Node ID': self.node_id, 'sChains on node': schains_on_node,
'Empty sChain structs': schains_holes}, 'Monitoring sChains'))
threads = []
for schain in schains:
- if not schain['active']: continue
+ if not schain['active']:
+ continue
schain_thread = CustomThread(f'sChain monitor: {schain["name"]}', self.monitor_schain,
opts=schain, once=True)
schain_thread.start()
@@ -71,18 +78,19 @@ def monitor_schains(self, opts):
def monitor_schain(self, schain):
name = schain['name']
- checks = SChainChecks(name, self.node_id, log=True, failhook=capture_message).get_all()
+ owner = schain['owner']
+ checks = SChainChecks(name, self.node_id, log=True).get_all()
if not checks['data_dir']:
init_schain_dir(name)
if not checks['config']:
- self.init_schain_config(name)
- if not checks['dkg']:
- try:
- init_bls(self.skale.web3, self.skale, self.wallet, schain['name'])
- except FailedDKG:
- # todo: clean up here
- exit(1)
+ self.init_schain_config(name, owner)
+ #if not checks['dkg']:
+ # try:
+ # init_bls(self.skale.web3, self.skale, schain['name']) # todo!
+ # except FailedDKG:
+ # # todo: clean up here
+ # exit(1)
if not checks['volume']:
init_data_volume(schain)
if not checks['container']:
@@ -90,11 +98,11 @@ def monitor_schain(self, schain):
if not checks['ima_container']:
self.monitor_ima_container(schain)
- def init_schain_config(self, schain_name):
+ def init_schain_config(self, schain_name, schain_owner):
config_filepath = get_schain_config_filepath(schain_name)
if not os.path.isfile(config_filepath):
logger.warning(f'sChain config not found: {config_filepath}, trying to create.')
- schain_config = generate_schain_config(schain_name, self.node_id, self.skale)
+ schain_config = generate_schain_config(schain_name, schain_owner, self.node_id, self.skale)
save_schain_config(schain_config, schain_name)
def check_container(self, schain_name, volume_required=False):
diff --git a/core/schains/runner.py b/core/schains/runner.py
index 602240b7e..8678ad3c8 100644
--- a/core/schains/runner.py
+++ b/core/schains/runner.py
@@ -103,7 +103,7 @@ def add_config_volume(run_args):
if not run_args.get('volumes', None):
run_args['volumes'] = {}
# mount /skale_node_data
- run_args['volumes'][NODE_DATA_PATH_HOST] = {
+ run_args['volumes'][NODE_DATA_PATH_HOST] = {
'bind': NODE_DATA_PATH,
"mode": "ro"
}
diff --git a/requirements.txt b/requirements.txt
index 25fc8fec2..802fa4669 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -13,12 +13,11 @@ simple-crypt==4.1.7
pycryptodome==3.4.11
coincurve==12.0.0
-skale.py==2.0.dev10
-sgx.py==0.2.dev2
+skale.py==2.0.dev16
PyYAML==5.1.2
psutil==5.6.3
-sentry-sdk==0.11.2
-
colorful==0.5.4
+
+filelock==3.0.12
\ No newline at end of file
diff --git a/tests/__init__.py b/tests/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/tests/core/__init__.py b/tests/core/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/tests/core/schains/__init__.py b/tests/core/schains/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/tests/core/schains/runner.py b/tests/core/schains/runner.py
deleted file mode 100644
index c59a87a7e..000000000
--- a/tests/core/schains/runner.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from core.schains.runner import run_schain_container
-
-DEFAULT_SCHAIN_NAME = 'test'
-DEFAULT_SCHAIN_DATA_DIR = '/data_dir'
-DEFAULT_SCHAIN_STRUCT = {'name': DEFAULT_SCHAIN_NAME, 'partOfNode': 4}
-TEST_CONFIG_FILEPATH = '/skale_node_data/schains/test/config_test.json' # todo!
-
-DEFAULT_SCHAIN_ENV = {
- "SSL_KEY_PATH": 'NULL',
- "SSL_CERT_PATH": 'NULL',
- "HTTP_RPC_PORT": '18880',
- "HTTPS_RPC_PORT": '18881',
- "WS_RPC_PORT": '18882',
- "WSS_RPC_PORT": '18883',
-
- "SCHAIN_ID": DEFAULT_SCHAIN_NAME,
- "CONFIG_FILE": TEST_CONFIG_FILEPATH,
- "DATA_DIR": DEFAULT_SCHAIN_DATA_DIR
-}
-
-
-def test_run_schain_container(skale):
- container_name = run_schain_container(DEFAULT_SCHAIN_NAME, DEFAULT_SCHAIN_ENV)
-
diff --git a/tools/bls/dkg_client.py b/tools/bls/dkg_client.py
index a49157fd3..447a33639 100644
--- a/tools/bls/dkg_client.py
+++ b/tools/bls/dkg_client.py
@@ -22,34 +22,39 @@
import logging
import coincurve
-from time import sleep
+from skale.utils.web3_utils import wait_receipt
+
from tools.configs import NODE_DATA_PATH
sys.path.insert(0, NODE_DATA_PATH)
-from dkgpython import dkg
-from skale.utils.web3_utils import wait_receipt
+# from dkgpython import dkg # todo: uncomment
logger = logging.getLogger(__name__)
+
def bxor(b1, b2):
parts = []
for b1, b2 in zip(b1, b2):
parts.append(bytes([b1 ^ b2]))
return b''.join(parts)
+
def encrypt(plaintext, secret_key):
- plaintext_in_bytes = bytearray(int(plaintext).to_bytes(32, byteorder ='big'))
+ plaintext_in_bytes = bytearray(int(plaintext).to_bytes(32, byteorder='big'))
return bxor(plaintext_in_bytes, secret_key)
+
def decrypt(ciphertext, secret_key):
xor_val = bxor(ciphertext, secret_key)
ret_val = binascii.hexlify(xor_val)
return str(int(ret_val.decode(), 16))
+
class DkgVerificationError(Exception):
def __init__(self, msg):
super().__init__(msg)
+
def convert_g2_points_to_hex(data):
data_hexed = "0x"
for coord in data:
@@ -59,11 +64,12 @@ def convert_g2_points_to_hex(data):
temp = '0' + temp
data_hexed += temp
temp = hex(int(elem[1]))[2:]
- while len(temp) < 64 :
+ while len(temp) < 64:
temp = '0' + temp
data_hexed += temp
return data_hexed
+
def convert_g2_point_to_hex(data):
data_hexed = "0x"
for coord in data:
@@ -74,10 +80,12 @@ def convert_g2_point_to_hex(data):
data_hexed += temp
return data_hexed
+
class DKGClient:
- def __init__(self, node_id_dkg, node_id_contract, node_web3, skale, wallet, t, n, schain_name, public_keys, node_ids_dkg, node_ids_contract):
+ def __init__(self, node_id_dkg, node_id_contract, node_web3, skale, wallet, t, n,
+ schain_name, public_keys, node_ids_dkg, node_ids_contract):
self.schain_name = schain_name
- self.group_index = node_web3.sha3(text = self.schain_name)
+ self.group_index = node_web3.sha3(text=self.schain_name)
self.node_id_contract = node_id_contract
self.node_id_dkg = node_id_dkg
self.node_web3 = node_web3
diff --git a/tools/config_storage.py b/tools/config_storage.py
deleted file mode 100644
index 818b78934..000000000
--- a/tools/config_storage.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of SKALE Admin
-#
-# Copyright (C) 2019 SKALE Labs
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero 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 Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import os, json, logging
-logger = logging.getLogger(__name__)
-
-class ConfigStorage:
- def __init__(self, path, init={}):
- self.path = path
- self.init = init
- self.config = self.__safe_read_config()
-
- def __getitem__(self, item):
- return self.config[item]
-
- def __setitem__(self, key, value):
- self.config[key] = value
- self.update(self.config)
-
- def update_item_field(self, key, field, value):
- item = self.config[key]
- item[field] = value
- self.config[key] = item
- self.update(self.config)
-
- def update(self, new_config):
- config = self._read_config()
- config.update(new_config)
- self.config = config
- self._write_config(config)
- return config
-
- def get(self):
- return self.config
-
- def safe_get(self, item):
- try:
- return self.config[item]
- except KeyError:
- logger.debug(f'key {item} is not found in config {self.path}')
- return None
-
- def __safe_read_config(self):
- if not self.__check_config_file():
- self.__init_config_file()
- return self._read_config()
-
- def _read_config(self):
- with open(self.path, encoding='utf-8') as data_file:
- config = json.loads(data_file.read())
- return config
-
- def _write_config(self, config):
- with open(self.path, 'w') as data_file:
- json.dump(config, data_file, indent=2)
-
- def __check_config_file(self):
- return os.path.exists(self.path)
-
- def __init_config_file(self):
- self._write_config(self.init)
diff --git a/tools/configs/__init__.py b/tools/configs/__init__.py
index d04c2262c..895b9e55a 100644
--- a/tools/configs/__init__.py
+++ b/tools/configs/__init__.py
@@ -1,14 +1,14 @@
import os
-from tools.configs.flask import FLASK_DEBUG_MODE
LONG_LINE = '=' * 100
DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
+RUNNING_ON_HOST = os.environ.get('RUNNING_ON_HOST', False)
SKALE_DIR_HOST = os.environ['SKALE_DIR_HOST']
NODE_DATA_PATH_HOST = os.path.join(SKALE_DIR_HOST, 'node_data')
-if FLASK_DEBUG_MODE:
+if RUNNING_ON_HOST:
SKALE_VOLUME_PATH = SKALE_DIR_HOST
NODE_DATA_PATH = NODE_DATA_PATH_HOST
else:
@@ -16,7 +16,6 @@
NODE_DATA_PATH = '/skale_node_data'
-
CONFIG_FOLDER_NAME = 'config'
CONTRACTS_INFO_FOLDER_NAME = 'contracts_info'
diff --git a/tools/configs/containers.py b/tools/configs/containers.py
index d94065807..9107c477f 100644
--- a/tools/configs/containers.py
+++ b/tools/configs/containers.py
@@ -34,4 +34,4 @@
CONTAINER_NOT_FOUND = 'not_found'
EXITED_STATUS = 'exited'
-RUNNING_STATUS = 'running'
\ No newline at end of file
+RUNNING_STATUS = 'running'
diff --git a/tools/configs/filebeat.py b/tools/configs/filebeat.py
index c2b720b56..5b6ac2663 100644
--- a/tools/configs/filebeat.py
+++ b/tools/configs/filebeat.py
@@ -4,4 +4,4 @@
FILEBEAT_TEMPLATE_PATH = os.path.join(CONFIG_FOLDER, 'filebeat.yml.j2')
FILEBEAT_CONFIG_PATH = os.path.join(NODE_DATA_PATH, 'filebeat.yml')
-FILEBEAT_CONTAINER_NAME = 'monitor_filebeat'
\ No newline at end of file
+FILEBEAT_CONTAINER_NAME = 'monitor_filebeat'
diff --git a/tools/configs/flask.py b/tools/configs/flask.py
index de101c3e1..ed275e967 100644
--- a/tools/configs/flask.py
+++ b/tools/configs/flask.py
@@ -27,5 +27,3 @@
FLASK_DEBUG_MODE = os.environ['FLASK_DEBUG_MODE'] == 'True'
SKALE_LIB_NAME = 'skale.py'
-
-
diff --git a/tools/configs/lvm.py b/tools/configs/lvm.py
deleted file mode 100644
index 450cc43d7..000000000
--- a/tools/configs/lvm.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of SKALE Admin
-#
-# Copyright (C) 2019 SKALE Labs
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero 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 Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import os
-from tools.config import PROJECT_DIR
-
-LVM_SCRIPT_NAME = 'lvm.sh'
-LVM_SCRIPT_PATH = os.path.join(PROJECT_DIR, 'server', 'core', 'lvm', LVM_SCRIPT_NAME)
-
-VOL_GROUP_NAME = 'SkaleLVMVolGroup'
-#VOL_GROUP_NAME = 'LVMVolGroup'
\ No newline at end of file
diff --git a/tools/configs/resource_allocation.py b/tools/configs/resource_allocation.py
index 23bfdd438..ac43a0993 100644
--- a/tools/configs/resource_allocation.py
+++ b/tools/configs/resource_allocation.py
@@ -33,4 +33,4 @@
RESOURCE_ALLOCATION_FILEPATH = os.path.join(NODE_DATA_PATH, RESOURCE_ALLOCATION_FILENAME)
DISK_MOUNTPOINT_FILENAME = 'disk_mountpoint.txt'
-DISK_MOUNTPOINT_FILEPATH = os.path.join(NODE_DATA_PATH, DISK_MOUNTPOINT_FILENAME)
\ No newline at end of file
+DISK_MOUNTPOINT_FILEPATH = os.path.join(NODE_DATA_PATH, DISK_MOUNTPOINT_FILENAME)
diff --git a/tools/configs/schains.py b/tools/configs/schains.py
index 2a4c7ceb5..04a784fc9 100644
--- a/tools/configs/schains.py
+++ b/tools/configs/schains.py
@@ -23,7 +23,7 @@
SCHAINS_DIR_NAME = 'schains'
SCHAINS_DIR_PATH = os.path.join(NODE_DATA_PATH, SCHAINS_DIR_NAME)
-SCHAIN_OWNER_ALLOC = 1000000000000000000000 # todo: tmp!
+SCHAIN_OWNER_ALLOC = 1000000000000000000000 # todo: tmp!
NODE_OWNER_ALLOC = 1000000000000000000000 # todo: tmp!
DATA_DIR_NAME = 'data_dir'
diff --git a/tools/configs/web3.py b/tools/configs/web3.py
index 0a0bf1846..6e52cbd6e 100644
--- a/tools/configs/web3.py
+++ b/tools/configs/web3.py
@@ -20,5 +20,6 @@
import os
from tools.configs import CONTRACTS_INFO_FOLDER, MANAGER_CONTRACTS_INFO_NAME
+TM_URL = os.environ['TM_URL']
ENDPOINT = os.environ['ENDPOINT']
ABI_FILEPATH = os.path.join(CONTRACTS_INFO_FOLDER, MANAGER_CONTRACTS_INFO_NAME)
diff --git a/tools/custom_thread.py b/tools/custom_thread.py
index ff176f0a7..0fe176e58 100644
--- a/tools/custom_thread.py
+++ b/tools/custom_thread.py
@@ -51,9 +51,10 @@ def run(self):
def safe_run_func(self):
try:
self.func(self.opts)
- except Exception as e:
+ except Exception:
logger.exception(
- f'Error was occurred during the function execution: {self.func.__name__}. See full stacktrace below.')
+ f'Error was occurred during the function execution: {self.func.__name__}. \
+ See full stacktrace below.')
# raise e todo: handle
def join(self, timeout=None):
diff --git a/tools/docker_utils.py b/tools/docker_utils.py
index c8b7c2a10..ac69d8636 100644
--- a/tools/docker_utils.py
+++ b/tools/docker_utils.py
@@ -72,7 +72,7 @@ def data_volume_exists(self, name):
def create_data_volume(self, name, size=None):
driver_opts = {'size': str(size)} if size else None
logging.info(
- f'Creating volume, driver: convoy, size: {size}, name: {name}, driver_opts: {driver_opts}')
+ f'Creating volume - size: {size}, name: {name}, driver_opts: {driver_opts}')
volume = self.client.volumes.create(
name=name,
driver='convoy',
diff --git a/tools/helper.py b/tools/helper.py
index 8d6d81002..d93f5a1cf 100644
--- a/tools/helper.py
+++ b/tools/helper.py
@@ -25,17 +25,24 @@
from jinja2 import Environment
+
logger = logging.getLogger(__name__)
-def read_json(path):
- with open(path, encoding='utf-8') as data_file:
- return json.loads(data_file.read())
+def read_json(path, mode='r'):
+ with open(path, mode=mode, encoding='utf-8') as data_file:
+ return json.load(data_file)
def write_json(path, content):
with open(path, 'w') as outfile:
json.dump(content, outfile, indent=4)
+ outfile.close()
+
+
+def init_file(path, content=None):
+ if not os.path.exists(path):
+ write_json(path, content)
def files(path):
@@ -66,10 +73,6 @@ def format_output(res):
return res.stdout.decode('UTF-8').rstrip(), res.stderr.decode('UTF-8').rstrip()
-def get_sentry_env_name(manager_address):
- return f'manager@{manager_address}'
-
-
def read_file(path):
file = open(path, 'r')
text = file.read()
diff --git a/tools/local_wallet.py b/tools/local_wallet.py
deleted file mode 100644
index c49187a1f..000000000
--- a/tools/local_wallet.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of SKALE Admin
-#
-# Copyright (C) 2019 SKALE Labs
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero 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 Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-from tools.config import LOCAL_WALLET_FILEPATH
-from encrypted_storage import EncryptedStorage
-
-
-class LocalWallet():
- def __init__(self, password):
- self.filepath = LOCAL_WALLET_FILEPATH
- self.encrypted_storage = EncryptedStorage(LOCAL_WALLET_FILEPATH, password)
-
- def get(self):
- return self.encrypted_storage.get()
-
- def update(self, text):
- self.encrypted_storage.update(text)
diff --git a/tools/logger.py b/tools/logger.py
index 50552056f..8528fcc14 100644
--- a/tools/logger.py
+++ b/tools/logger.py
@@ -17,7 +17,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-import os
import sys
import logging
from logging import Formatter, StreamHandler
diff --git a/tools/sgx_utils.py b/tools/sgx_utils.py
index 98e411c9d..5db51e349 100644
--- a/tools/sgx_utils.py
+++ b/tools/sgx_utils.py
@@ -18,19 +18,37 @@
# along with this program. If not, see .
import os
+import logging
+
from sgx import SgxClient
-sgx_key_config_item = 'sgx_key_name'
+from tools.str_formatters import arguments_list_string
-def generate_sgx_key(config):
- if not os.environ.get('SGX_SERVER_URL') or config.safe_get(sgx_key_config_item):
- return
- sgx = SgxClient(os.environ['SGX_SERVER_URL'])
- key_name = sgx.generate_key().keyName
- save_sgx_key(key_name, config)
+logger = logging.getLogger(__name__)
+
+SGX_KEY_CONFIG_NAME = 'sgx_key_name'
+SGX_SERVER_URL = os.environ.get('SGX_SERVER_URL')
+
+class SGXConnecionError(Exception):
+ """Raised when admin couldn't establish connection with SGX server"""
+
+
+def generate_sgx_key(config):
+ if not SGX_SERVER_URL:
+ raise SGXConnecionError('SGX server URL is not provided')
+ if not config.sgx_key_name:
+ sgx = SgxClient(SGX_SERVER_URL)
+ key_info = sgx.generate_key()
+ logger.info(arguments_list_string({
+ 'Name': key_info.name,
+ 'Address': key_info.address
+ }, 'Generated new SGX key'))
+ config.sgx_key_name = key_info.name
-def save_sgx_key(key_name, config):
- config.update({sgx_key_config_item: key_name})
+def sgx_server_text():
+ if SGX_SERVER_URL:
+ return SGX_SERVER_URL
+ return 'Not connected'
diff --git a/tools/token_utils.py b/tools/token_utils.py
index bfbe321b3..87957f8fa 100644
--- a/tools/token_utils.py
+++ b/tools/token_utils.py
@@ -17,29 +17,27 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+import os
import logging
import secrets
-from tools.config_storage import ConfigStorage
+from tools.str_formatters import arguments_list_string
+from tools.helper import write_json, read_json
from tools.configs import TOKENS_FILEPATH
logger = logging.getLogger(__name__)
-class TokenUtils():
- def __init__(self, filepath=TOKENS_FILEPATH):
- self.filepath = filepath
- self.token_storage = ConfigStorage(filepath)
+def init_user_token():
+ if not os.path.exists(TOKENS_FILEPATH):
+ token = generate_user_token()
+ logger.info(arguments_list_string({'Token': token}, 'Generated registration token'))
+ write_json(TOKENS_FILEPATH, {'token': token})
+ return token
+ else:
+ tokens = read_json(TOKENS_FILEPATH)
+ return tokens['token']
- def add_token(self):
- token = self.generate_new_token()
- self.save_token(token)
- def generate_new_token(self, len=40):
- return secrets.token_hex(len)
-
- def save_token(self, token):
- self.token_storage.update({'token': token})
-
- def get_token(self):
- return self.token_storage.safe_get('token')
\ No newline at end of file
+def generate_user_token(token_len=40):
+ return secrets.token_hex(token_len)
diff --git a/tools/wallet_utils.py b/tools/wallet_utils.py
new file mode 100644
index 000000000..6dced63ac
--- /dev/null
+++ b/tools/wallet_utils.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of SKALE Admin
+#
+# Copyright (C) 2019 SKALE Labs
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+# todo: move to smart contracts
+DEPOSIT_AMOUNT_SKL = 100
+DEPOSIT_AMOUNT_ETH = 0.2
+
+DEPOSIT_AMOUNT_SKL_WEI = DEPOSIT_AMOUNT_SKL * (10 ** 18)
+DEPOSIT_AMOUNT_ETH_WEI = int(DEPOSIT_AMOUNT_ETH * (10 ** 18))
+
+
+def wallet_with_balance(skale): # todo: move to the skale.py
+ address = skale.wallet.address
+ eth_balance_wei = skale.web3.eth.getBalance(address)
+ skale_balance_wei = skale.token.get_balance(address)
+ return {
+ 'address': address,
+ 'eth_balance_wei': eth_balance_wei,
+ 'skale_balance_wei': skale_balance_wei,
+ 'eth_balance': str(skale.web3.fromWei(eth_balance_wei, 'ether')),
+ 'skale_balance': str(skale.web3.fromWei(skale_balance_wei, 'ether'))
+ }
+
+
+def check_required_balance(skale): # todo: move to the skale.py
+ balances = wallet_with_balance(skale)
+ return int(balances['eth_balance_wei']) >= DEPOSIT_AMOUNT_ETH_WEI and int(balances[
+ 'skale_balance_wei']) >= DEPOSIT_AMOUNT_SKL_WEI
diff --git a/web/base_model.py b/web/base_model.py
index a66e3018f..4ab642f86 100644
--- a/web/base_model.py
+++ b/web/base_model.py
@@ -25,5 +25,6 @@
class BaseModel(Model):
database = database
+
class Meta:
database = database
diff --git a/web/helper.py b/web/helper.py
index 1e55da48c..ee99c8637 100644
--- a/web/helper.py
+++ b/web/helper.py
@@ -58,4 +58,3 @@ def inner(*args, **kwargs):
return f(*args, **kwargs)
return inner
-
diff --git a/web/routes/auth.py b/web/routes/auth.py
index 7f74fd412..fb4deb62e 100644
--- a/web/routes/auth.py
+++ b/web/routes/auth.py
@@ -40,11 +40,10 @@ def get_user_info():
def join():
request_data = request.json
if not request_data.get('username') or not request_data.get(
- 'password') or not request_data.get(
- 'token'):
+ 'password') or not request_data.get('token'):
return construct_err_response(400, [{'msg': 'Wrong data provided'}])
- if request_data['token'] != token: # todo: check token from file!
+ if request_data['token'] != token:
return construct_err_response(400, [{'msg': 'Token not match'}])
user, err = User.join(request_data['username'], request_data['password'], token)
diff --git a/web/routes/metrics.py b/web/routes/metrics.py
index c8d8b61cb..fa51927d7 100644
--- a/web/routes/metrics.py
+++ b/web/routes/metrics.py
@@ -23,7 +23,6 @@
from flask import Blueprint, request
from core.db import BountyEvent
-from core.node.utils import get_node_id
from web.helper import construct_ok_response, login_required
logger = logging.getLogger(__name__)
@@ -36,11 +35,11 @@ def construct_metrics_bp(skale, config):
metrics_bp = Blueprint('metrics', __name__)
def get_start_date():
- node_id = get_node_id(config)
+ node_id = config.id
return skale.nodes_data.get(node_id)['start_date']
def get_last_reward_date():
- node_id = get_node_id(config)
+ node_id = config.id
return skale.nodes_data.get(node_id)['last_reward_date']
def find_block_for_tx_stamp(tx_stamp, lo=0, hi=None):
@@ -82,7 +81,7 @@ def get_bounty_from_db(is_from_begin=True, limit=None):
return bounties_list
def get_bounty_from_events(start_date, end_date=None, is_limited=True):
- node_id = get_node_id(config)
+ node_id = config.id
bounties = []
start_block_number = find_block_for_tx_stamp(start_date)
cur_block_number = skale.web3.eth.blockNumber
diff --git a/web/routes/node_info.py b/web/routes/node_info.py
index 446f1595e..d6041fcbf 100644
--- a/web/routes/node_info.py
+++ b/web/routes/node_info.py
@@ -30,7 +30,7 @@
logger = logging.getLogger(__name__)
-def construct_node_info_bp(skale, wallet, docker_utils):
+def construct_node_info_bp(skale, docker_utils):
node_info_bp = Blueprint('node_info', __name__)
@node_info_bp.route('/get-rpc-credentials', methods=['GET'])
@@ -66,7 +66,6 @@ def about_node():
'network': {
'endpoint': ENDPOINT
},
- 'local_wallet': wallet.get_with_balance()
}
return construct_ok_response(node_about)
diff --git a/web/routes/nodes.py b/web/routes/nodes.py
index 9ad519449..813edf82b 100644
--- a/web/routes/nodes.py
+++ b/web/routes/nodes.py
@@ -35,12 +35,11 @@ def construct_nodes_bp(skale, node, docker_utils):
@login_required
def node_info():
logger.debug(request)
- node_info = node.get_node_info()
- return construct_ok_response(node_info)
+ return construct_ok_response(node.info)
@nodes_bp.route('/create-node', methods=['POST'])
@login_required
- def create_node():
+ def register_node():
logger.debug(request)
if not request.json:
abort(400)
@@ -62,7 +61,7 @@ def create_node():
logger.error(error_msg)
return construct_err_response(HTTPStatus.BAD_REQUEST, [error_msg])
- res = node.create(ip, public_ip, port, name)
+ res = node.register(ip, public_ip, port, name)
if res['status'] != 1:
return construct_err_response(HTTPStatus.INTERNAL_SERVER_ERROR, res['errors'])
return construct_response(HTTPStatus.CREATED, res['data'])
@@ -98,4 +97,4 @@ def skale_containers_list():
containers_list = docker_utils.get_all_skale_containers(all=all, format=True)
return construct_ok_response(containers_list)
- return nodes_bp
\ No newline at end of file
+ return nodes_bp
diff --git a/web/routes/schains.py b/web/routes/schains.py
index 96b8bb78f..5534d6dc3 100644
--- a/web/routes/schains.py
+++ b/web/routes/schains.py
@@ -20,27 +20,22 @@
import logging
from http import HTTPStatus
-from flask import Blueprint, request, abort
+from flask import Blueprint, request
-import skale.utils.helper as Helper
from core.schains.helper import get_schain_config
-from web.helper import construct_ok_response, construct_err_response, construct_response, \
- login_required
+from web.helper import construct_ok_response, construct_err_response, login_required
logger = logging.getLogger(__name__)
-def construct_schains_bp(skale, wallet, docker_utils, node):
+def construct_schains_bp(skale, config, docker_utils):
schains_bp = Blueprint('schains', __name__)
@schains_bp.route('/get-owner-schains', methods=['GET'])
@login_required
def owner_schains():
logger.debug(request)
-
- local_wallet = wallet.get()
- schains = skale.schains_data.get_schains_for_owner(local_wallet['address'])
-
+ schains = skale.schains_data.get_schains_for_owner(skale.wallet.address)
for schain in schains:
nodes = skale.schains_data.get_nodes_for_schain_config(schain['name'])
schain['nodes'] = nodes
@@ -50,45 +45,25 @@ def owner_schains():
@login_required
def get_schain_config_route():
logger.debug(request)
-
schain_name = request.args.get('schain-name')
# todo: handle - if schain name is empty or invalid
schain_config = get_schain_config(schain_name)
skale_schain_config = schain_config['skaleConfig']
return construct_ok_response(skale_schain_config)
- @schains_bp.route('/create-schain', methods=['POST'])
- @login_required
- def create_schain():
- logger.debug(request)
- if not request.json:
- abort(400)
-
- lifetime_years = 1
- lifetime_seconds = lifetime_years * 366 * 86400
- type_of_nodes = 4
-
- price_in_wei = skale.schains.get_schain_price(type_of_nodes, lifetime_seconds)
- name = Helper.generate_random_name()
-
- res = skale.manager.create_schain(lifetime_seconds, type_of_nodes, price_in_wei, name)
- receipt = Helper.await_receipt(skale.web3, res['tx'])
- res = {'res': receipt['status']}
- return construct_response(HTTPStatus.CREATED, res)
-
@schains_bp.route('/containers/schains/list', methods=['GET'])
@login_required
def schains_containers_list():
logger.debug(request)
- all = request.args.get('all') == 'True'
- containers_list = docker_utils.get_all_schain_containers(all=all, format=True)
+ _all = request.args.get('all') == 'True'
+ containers_list = docker_utils.get_all_schain_containers(all=_all, format=True)
return construct_ok_response(containers_list)
@schains_bp.route('/schains/list', methods=['GET'])
@login_required
def node_schains_list():
logger.debug(request)
- node_id = node.get_node_id()
+ node_id = config.id
if node_id is None:
return construct_err_response(HTTPStatus.BAD_REQUEST, ['No node installed'])
schains_list = skale.schains_data.get_schains_for_node(node_id)
diff --git a/web/routes/security.py b/web/routes/security.py
index 0c145fd19..f102823dd 100644
--- a/web/routes/security.py
+++ b/web/routes/security.py
@@ -63,7 +63,6 @@ def upload_ssl_certificate():
return construct_ok_response(1)
-
@security_bp.route('/certificates-info', methods=['GET'])
@login_required
def get_certificates_info():
diff --git a/web/routes/validators.py b/web/routes/validators.py
index 85a8f91aa..368798ec4 100644
--- a/web/routes/validators.py
+++ b/web/routes/validators.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import logging
-from http import HTTPStatus
from flask import Blueprint, request
from playhouse.shortcuts import model_to_dict
@@ -26,12 +25,11 @@
from core.db import BountyEvent
from tools.configs import DATETIME_FORMAT
-from core.node.utils import get_node_id
logger = logging.getLogger(__name__)
-def construct_validators_bp(skale, config, wallet):
+def construct_validators_bp(skale, config):
validators_bp = Blueprint('validators', __name__)
@validators_bp.route('/bounty-info', methods=['GET'])
@@ -52,20 +50,12 @@ def bounty_info():
@login_required
def validators_info():
logger.debug(request)
-
- node_id = get_node_id(config)
- # todo: handle no node_id
-
- print(skale.validators_data.get_validated_array)
-
- res = skale.validators_data.get_validated_array(node_id, wallet.get()['address'])
- print(res)
-
+ # todo: handle no config.id
+ res = skale.validators_data.get_validated_array(config.id, skale.wallet.address)
validators = {
'validating': res,
- 'validated_by': 2
+ 'validated_by': None
}
-
return construct_ok_response({'validators': validators})
return validators_bp
diff --git a/web/routes/wallet.py b/web/routes/wallet.py
index b34ffb784..d68816439 100644
--- a/web/routes/wallet.py
+++ b/web/routes/wallet.py
@@ -18,31 +18,23 @@
# along with this program. If not, see .
import logging
-from http import HTTPStatus
from flask import Blueprint, request
-from web.helper import construct_ok_response, construct_response, login_required
+from web.helper import construct_ok_response, login_required
+from tools.wallet_utils import wallet_with_balance
logger = logging.getLogger(__name__)
-def construct_wallet_bp(wallet):
+def construct_wallet_bp(skale):
wallet_bp = Blueprint('wallet', __name__)
- @wallet_bp.route('/create-wallet', methods=['POST'])
- @login_required
- def create_wallet():
- logger.debug(request)
- res = wallet.get_or_generate()
- return construct_response(HTTPStatus.CREATED, res)
-
@wallet_bp.route('/load-wallet', methods=['GET'])
@login_required
def load_wallet():
logger.debug(request)
- wallet.get_or_generate() # todo: tmp, remove later!
- res = wallet.get_with_balance()
+ res = wallet_with_balance(skale)
return construct_ok_response(res)
return wallet_bp
diff --git a/web/user.py b/web/user.py
index e3ad930fd..a6331bd98 100644
--- a/web/user.py
+++ b/web/user.py
@@ -65,7 +65,6 @@ def login(cls, username, password, user_session):
user_session.auth(user)
return True, None
-
def info(self):
return {
'username': self.username,