From f274b3cb4c820eaa1a6ba354d1b826b37bacc87e Mon Sep 17 00:00:00 2001 From: Kieran Prasch Date: Wed, 7 Mar 2018 19:55:12 -0800 Subject: [PATCH] [KMS-ETH]- Miner and Token config classes for contract deployers --- nkms_eth/actors.py | 5 +- nkms_eth/agents.py | 23 +-------- nkms_eth/config.py | 74 ++++++++++++++++++++++++++-- nkms_eth/deployers.py | 111 ++++++++++++++---------------------------- tests/conftest.py | 2 +- 5 files changed, 111 insertions(+), 104 deletions(-) diff --git a/nkms_eth/actors.py b/nkms_eth/actors.py index 582ccecb7..2add729c0 100644 --- a/nkms_eth/actors.py +++ b/nkms_eth/actors.py @@ -223,10 +223,7 @@ class Miner(Actor): class PolicyAuthor(Actor): """Alice""" - def __init__(self, address: bytes, policy_agent: PolicyAgent): - - if policy_agent.is_deployed is False: - raise PolicyAgent.ContractDeploymentError('PolicyManager contract not deployed.') + def __init__(self, address: bytes, policy_agent): self.policy_agent = policy_agent super().__init__(address) self._arrangements = OrderedDict() # Track authored policies by id diff --git a/nkms_eth/agents.py b/nkms_eth/agents.py index 4bdeb975f..183ca5f9a 100644 --- a/nkms_eth/agents.py +++ b/nkms_eth/agents.py @@ -1,5 +1,4 @@ import random -from enum import Enum from typing import Set, Generator, List from nkms_eth.actors import PolicyAuthor @@ -37,25 +36,6 @@ class MinerAgent(ContractAgent): __deployer = MinerEscrowDeployer _contract_name = __deployer.contract_name - class MinerInfoField(Enum): - MINERS_LENGTH = 0 - MINER = 1 - VALUE = 2 - DECIMALS = 3 - LOCKED_VALUE = 4 - RELEASE = 5 - MAX_RELEASE_PERIODS = 6 - RELEASE_RATE = 7 - CONFIRMED_PERIODS_LENGTH = 8 - CONFIRMED_PERIOD = 9 - CONFIRMED_PERIOD_LOCKED_VALUE = 10 - LAST_ACTIVE_PERIOD_F = 11 - DOWNTIME_LENGTH = 12 - DOWNTIME_START_PERIOD = 13 - DOWNTIME_END_PERIOD = 14 - MINER_IDS_LENGTH = 15 - MINER_ID = 16 - class NotEnoughUrsulas(Exception): pass @@ -77,7 +57,6 @@ class MinerAgent(ContractAgent): count = self.call().getMinerInfo(self.MinerInfoField.MINERS_LENGTH.value, self.null_addr, 0).encode('latin-1') count = self._blockchain._chain.web3.toInt(count) - for index in range(count): addr = self.call().getMinerInfo(self.MinerInfoField.MINER.value, self.null_addr, index).encode('latin-1') yield self._blockchain._chain.web3.toChecksumAddress(addr) @@ -107,8 +86,8 @@ class MinerAgent(ContractAgent): system_random = random.SystemRandom() n_select = round(quantity*additional_ursulas) # Select more Ursulas - n_tokens = self.call().getAllLockedTokens() + n_tokens = self.call().getAllLockedTokens() # Check for locked tokens if not n_tokens > 0: raise self.NotEnoughUrsulas('There are no locked tokens.') diff --git a/nkms_eth/config.py b/nkms_eth/config.py index 030a323ae..4f13f794f 100644 --- a/nkms_eth/config.py +++ b/nkms_eth/config.py @@ -1,3 +1,4 @@ +from enum import Enum from os.path import dirname, join, abspath import appdirs @@ -6,13 +7,80 @@ import populus import nkms_eth +class TokenConfig: + __subdigits = 18 + _M = 10 ** __subdigits + __premine = int(1e9) * _M + __saturation = int(1e10) * _M + _reward = __saturation - __premine + + @property + def saturation(self): + return self.__saturation + + +class MinerConfig: + __hours_per_period = 1 # 24 Hours TODO + __min_release_periods = 1 # 30 Periods + __max_awarded_periods = 365 # Periods + + __min_allowed_locked = 10 ** 6 + __max_allowed_locked = 10 ** 7 * TokenConfig._M + + __reward = TokenConfig._reward + __null_addr = '0x' + '0' * 40 + + __mining_coeff = [ + __hours_per_period, + 2 * 10 ** 7, + __max_awarded_periods, + __max_awarded_periods, + __min_release_periods, + __min_allowed_locked, + __max_allowed_locked + ] + + class MinerInfoField(Enum): + MINERS_LENGTH = 0 + MINER = 1 + VALUE = 2 + DECIMALS = 3 + LOCKED_VALUE = 4 + RELEASE = 5 + MAX_RELEASE_PERIODS = 6 + RELEASE_RATE = 7 + CONFIRMED_PERIODS_LENGTH = 8 + CONFIRMED_PERIOD = 9 + CONFIRMED_PERIOD_LOCKED_VALUE = 10 + LAST_ACTIVE_PERIOD_F = 11 + DOWNTIME_LENGTH = 12 + DOWNTIME_START_PERIOD = 13 + DOWNTIME_END_PERIOD = 14 + MINER_IDS_LENGTH = 15 + MINER_ID = 16 + + @property + def null_address(self): + return self.__null_addr + + @property + def mining_coefficient(self): + return self.__mining_coeff + + @property + def reward(self): + return self.__reward + + class PopulusConfig: - def __init__(self): - self._python_project_name = 'nucypher-kms' + def __init__(self, project_name='nucypher-kms', registrar_path=None): + self._python_project_name = project_name # This config is persistent and is created in user's .local directory - self._registrar_path = join(appdirs.user_data_dir(self._python_project_name), 'registrar.json') + if registrar_path is None: + registrar_path = join(appdirs.user_data_dir(self._python_project_name), 'registrar.json') + self._registrar_path = registrar_path # Populus project config self._project_dir = join(dirname(abspath(nkms_eth.__file__)), 'project') diff --git a/nkms_eth/deployers.py b/nkms_eth/deployers.py index 9713069ba..21e41adb1 100644 --- a/nkms_eth/deployers.py +++ b/nkms_eth/deployers.py @@ -1,24 +1,19 @@ from typing import Tuple -from nkms_eth.agents import MinerAgent from nkms_eth.base import ContractDeployer -from nkms_eth.token import NuCypherKMSTokenAgent +from nkms_eth.config import MinerConfig, TokenConfig from .blockchain import TheBlockchain addr = str class NuCypherKMSTokenDeployer(ContractDeployer): - __contract_name = 'NuCypherKMSToken' - __subdigits = 18 - _M = 10 ** __subdigits - __premine = int(1e9) * _M - __saturation = int(1e10) * _M - _reward = __saturation - __premine + _contract_name = 'NuCypherKMSToken' - def __init__(self, blockchain: TheBlockchain): + def __init__(self, blockchain: TheBlockchain, config=TokenConfig()): super().__init__(blockchain=blockchain) self.__creator = self._blockchain._chain.web3.eth.accounts[0] + self._token_config = config @property def origin(self): @@ -33,17 +28,17 @@ class NuCypherKMSTokenDeployer(ContractDeployer): Deployment can only ever be executed exactly once! """ - if self._armed is False: + if self.is_armed is False: raise self.ContractDeploymentError('use .arm() to arm the contract, then .deploy().') - if self._contract is not None: + if self.is_deployed is True: class_name = self.__class__.__name__ message = '{} contract already deployed, use .get() to retrieve it.'.format(class_name) raise self.ContractDeploymentError(message) the_nucypherKMS_token_contract, deployment_txhash = self._blockchain._chain.provider.deploy_contract( - self.__contract_name, - deploy_args=[self.__saturation], + self._contract_name, + deploy_args=[self._token_config.saturation], deploy_transaction={'from': self.origin}) self._blockchain._chain.wait.for_receipt(deployment_txhash, timeout=self._blockchain._timeout) @@ -51,80 +46,44 @@ class NuCypherKMSTokenDeployer(ContractDeployer): self._contract = the_nucypherKMS_token_contract return deployment_txhash - def _airdrop(self, amount: int): - """Airdrops from creator address to all other addresses!""" - - _creator, *addresses = self._blockchain._chain.web3.eth.accounts - - def txs(): - for address in addresses: - yield self._contract.transact({'from': self.origin}).transfer(address, amount * (10 ** 6)) - - for tx in txs(): - self._blockchain._chain.wait.for_receipt(tx, timeout=10) - - return self - class PolicyManagerDeployer(ContractDeployer): - __contract_name = 'PolicyManager' + _contract_name = 'PolicyManager' - def __init__(self, escrow: MinerAgent): - super().__init__(escrow) - self.escrow = escrow - self.token = escrow._token + def __init__(self, miner_agent): + super().__init__(miner_agent) + self.miner_agent = miner_agent + self.token_agent = miner_agent._token_agent def deploy(self) -> Tuple[str, str]: - if self.armed is False: + if self.is_armed is False: raise self.ContractDeploymentError('PolicyManager contract not armed') if self.is_deployed is True: raise self.ContractDeploymentError('PolicyManager contract already deployed') # Creator deploys the policy manager - the_policy_manager_contract, deploy_txhash = self.blockchain._chain.provider.deploy_contract( - self.__contract_name, - deploy_args=[self.escrow._contract.address], - deploy_transaction={'from': self.token.creator}) + the_policy_manager_contract, deploy_txhash = self._blockchain._chain.provider.deploy_contract( + self._contract_name, + deploy_args=[self.miner_agent._contract.address], + deploy_transaction={'from': self.token_agent.creator}) self._contract = the_policy_manager_contract - set_txhash = self.escrow.transact({'from': self.token.creator}).setPolicyManager(the_policy_manager_contract.address) - self.blockchain._chain.wait.for_receipt(set_txhash) + set_txhash = self.miner_agent.transact({'from': self.token_agent.creator}).setPolicyManager(the_policy_manager_contract.address) + self._blockchain._chain.wait.for_receipt(set_txhash) return deploy_txhash, set_txhash - class MinerEscrowDeployer(ContractDeployer): - __contract_name = 'MinersEscrow' - __hours_per_period = 1 # 24 Hours TODO - __min_release_periods = 1 # 30 Periods - __max_awarded_periods = 365 # Periods - __min_allowed_locked = 10 ** 6 - __max_allowed_locked = 10 ** 7 * NuCypherKMSTokenDeployer._M - __reward = NuCypherKMSTokenDeployer._reward - __null_addr = '0x' + '0' * 40 + _contract_name = 'MinersEscrow' - __mining_coeff = [ - __hours_per_period, - 2 * 10 ** 7, - __max_awarded_periods, - __max_awarded_periods, - __min_release_periods, - __min_allowed_locked, - __max_allowed_locked - ] - - def __init__(self, token: NuCypherKMSTokenAgent): - super().__init__(token) - self._token = token - - @property - @classmethod - def null_address(cls): - return cls.__null_addr + def __init__(self, token_agent, config=MinerConfig()): + super().__init__(token_agent) + self._token_agent = token_agent + self._config = config def deploy(self) -> Tuple[str, str, str]: """ @@ -137,25 +96,29 @@ class MinerEscrowDeployer(ContractDeployer): Returns transaction hashes in a tuple: deploy, reward, and initialize. """ - if self._armed is False: + if self.is_armed is False: raise self.ContractDeploymentError('use .arm() to arm the contract, then .deploy().') - if self._contract is not None: + if self.is_deployed is True: class_name = self.__class__.__name__ message = '{} contract already deployed, use .get() to retrieve it.'.format(class_name) raise self.ContractDeploymentError(message) - the_escrow_contract, deploy_txhash = self._blockchain._chain.provider.deploy_contract(self.__contract_name, - deploy_args=[self._token._contract.address] + self.__mining_coeff, - deploy_transaction={'from': self._token._creator}) + deploy_args = [self._token_agent._contract.address] + self._config.mining_coefficient + deploy_tx = {'from': self._token_agent._creator} + + the_escrow_contract, deploy_txhash = self._blockchain._chain.provider.deploy_contract(self._contract_name, + deploy_args=deploy_args, + deploy_transaction=deploy_tx) self._blockchain._chain.wait.for_receipt(deploy_txhash, timeout=self._blockchain._timeout) - self._contract = the_escrow_contract + self.__contract = the_escrow_contract - reward_txhash = self._token.transact({'from': self._token.origin}).transfer(self._contract.address, self.__reward) + reward_txhash = self._token_agent.transact({'from': self._token_agent.origin}).transfer(self.__contract.address, + self._config.reward) self._blockchain._chain.wait.for_receipt(reward_txhash, timeout=self._blockchain._timeout) - init_txhash = self._contract.transact({'from': self._token.origin}).initialize() + init_txhash = self.__contract.transact({'from': self._token_agent.origin}).initialize() self._blockchain._chain.wait.for_receipt(init_txhash, timeout=self._blockchain._timeout) return deploy_txhash, reward_txhash, init_txhash diff --git a/tests/conftest.py b/tests/conftest.py index 039d44ceb..834c47a2d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,7 +2,7 @@ import pytest from nkms_eth.agents import NuCypherKMSTokenAgent, MinerAgent from nkms_eth.deployers import NuCypherKMSTokenDeployer -from tests.utilities import TesterBlockchain, MockMinerEscrow +from tests.utilities import TesterBlockchain, MockMinerEscrowDeployer @pytest.fixture(scope='function')