diff --git a/docs/source/architecture/contracts.md b/docs/source/architecture/contracts.md
index 80a9689a3..573932157 100644
--- a/docs/source/architecture/contracts.md
+++ b/docs/source/architecture/contracts.md
@@ -122,3 +122,9 @@ All tokens will be unlocked after a specified time and the user can retrieve the
When the user wants to become a staker - they use the `PreallocationEscrow` contract as a proxy for the `StakingEscrow` and `PolicyManager` contracts.
+## Contracts Versioning
+Upgradeable contracts, such as `Adjudicator`, `StakingEscrow`, `PolicyManager` and `StakingInterface`, have their version specified in contract doc inside @dev.
+Version format is `|vi.j.k|`, where `i` - major version, `j` - minor version, `k` - patch, for example `|v1.2.3|`:
+* Different major versions mean different forks and they are not upgradeable
+* Minor versions relate to any signatures or state changes inside contract, contracts are upgradeable between minor versions, but have different ABI and follows different agent layers
+* Patches involve changes inside function(s) with signature(s) untouched. All patches with a common minor version can be upgraded from one to another without other changes
diff --git a/nucypher/blockchain/eth/actors.py b/nucypher/blockchain/eth/actors.py
index f0db95dd5..d70feb2fc 100644
--- a/nucypher/blockchain/eth/actors.py
+++ b/nucypher/blockchain/eth/actors.py
@@ -229,6 +229,7 @@ class ContractAdministrator(NucypherTokenActor):
gas_limit: int = None,
plaintext_secret: str = None,
bare: bool = False,
+ ignore_deployed: bool = False,
progress=None,
*args, **kwargs,
) -> Tuple[dict, BaseContractDeployer]:
@@ -250,17 +251,24 @@ class ContractAdministrator(NucypherTokenActor):
receipts = deployer.deploy(secret_hash=secret_hash,
gas_limit=gas_limit,
initial_deployment=is_initial_deployment,
- progress=progress)
+ progress=progress,
+ ignore_deployed=ignore_deployed)
else:
receipts = deployer.deploy(gas_limit=gas_limit, progress=progress)
return receipts, deployer
- def upgrade_contract(self, contract_name: str, existing_plaintext_secret: str, new_plaintext_secret: str) -> dict:
+ def upgrade_contract(self,
+ contract_name: str,
+ existing_plaintext_secret: str,
+ new_plaintext_secret: str,
+ ignore_deployed: bool = False
+ ) -> dict:
Deployer = self.__get_deployer(contract_name=contract_name)
deployer = Deployer(registry=self.registry, deployer_address=self.deployer_address)
new_secret_hash = keccak(bytes(new_plaintext_secret, encoding='utf-8'))
receipts = deployer.upgrade(existing_secret_plaintext=bytes(existing_plaintext_secret, encoding='utf-8'),
- new_secret_hash=new_secret_hash)
+ new_secret_hash=new_secret_hash,
+ ignore_deployed=ignore_deployed)
return receipts
def retarget_proxy(self, contract_name: str, target_address: str, existing_plaintext_secret: str, new_plaintext_secret: str):
@@ -293,13 +301,15 @@ class ContractAdministrator(NucypherTokenActor):
secrets: dict,
interactive: bool = True,
emitter: StdoutEmitter = None,
- etherscan: bool = False) -> dict:
+ etherscan: bool = False,
+ ignore_deployed: bool = False) -> dict:
"""
:param secrets: Contract upgrade secrets dictionary
:param interactive: If True, wait for keypress after each contract deployment
:param emitter: A console output emitter instance. If emitter is None, no output will be echoed to the console.
:param etherscan: Open deployed contracts in Etherscan
+ :param ignore_deployed: Ignore already deployed contracts if exist
:return: Returns a dictionary of deployment receipts keyed by contract name
"""
@@ -336,7 +346,8 @@ class ContractAdministrator(NucypherTokenActor):
receipts, deployer = self.deploy_contract(contract_name=deployer_class.contract_name,
plaintext_secret=secrets[deployer_class.contract_name],
gas_limit=gas_limit,
- progress=bar)
+ progress=bar,
+ ignore_deployed=ignore_deployed)
if emitter:
blockchain = BlockchainInterfaceFactory.get_interface()
diff --git a/nucypher/blockchain/eth/agents.py b/nucypher/blockchain/eth/agents.py
index 03cf8eeb6..ece261a53 100644
--- a/nucypher/blockchain/eth/agents.py
+++ b/nucypher/blockchain/eth/agents.py
@@ -97,7 +97,7 @@ class EthereumContractAgent:
if contract is None: # Fetch the contract
contract = self.blockchain.get_contract_by_name(registry=self.registry,
- name=self.registry_contract_name,
+ contract_name=self.registry_contract_name,
proxy_name=self._proxy_name,
use_proxy_address=self._forward_address)
self.__contract = contract
diff --git a/nucypher/blockchain/eth/deployers.py b/nucypher/blockchain/eth/deployers.py
index e723122e5..8fc917fd2 100644
--- a/nucypher/blockchain/eth/deployers.py
+++ b/nucypher/blockchain/eth/deployers.py
@@ -34,7 +34,8 @@ from nucypher.blockchain.eth.agents import (
)
from nucypher.blockchain.eth.constants import DISPATCHER_CONTRACT_NAME
from nucypher.blockchain.eth.decorators import validate_secret, validate_checksum_address
-from nucypher.blockchain.eth.interfaces import BlockchainDeployerInterface, BlockchainInterfaceFactory
+from nucypher.blockchain.eth.interfaces import BlockchainDeployerInterface, BlockchainInterfaceFactory, \
+ VersionedContract
from nucypher.blockchain.eth.registry import AllocationRegistry, BaseContractRegistry
@@ -105,15 +106,25 @@ class BaseContractDeployer:
def dispatcher(self):
return self.__proxy_contract
- @property
- def is_deployed(self) -> bool:
- return bool(self._contract is not CONTRACT_NOT_DEPLOYED)
-
@property
def ready_to_deploy(self) -> bool:
return bool(self.__ready_to_deploy is True)
- def check_deployment_readiness(self, fail=True) -> Tuple[bool, list]:
+ def is_deployed(self, contract_version: str = None) -> bool:
+ try:
+ self.registry.search(contract_name=self.contract_name, contract_version=contract_version)
+ except BaseContractRegistry.UnknownContract:
+ return False
+ except BaseContractRegistry.NoRegistry:
+ return False
+ else:
+ return True
+
+ def check_deployment_readiness(self,
+ contract_version: str = None,
+ ignore_deployed=False,
+ fail=True
+ ) -> Tuple[bool, list]:
"""
Iterates through a set of rules required for an ethereum
contract deployer to be eligible for deployment returning a
@@ -128,8 +139,12 @@ class BaseContractDeployer:
if self.__ready_to_deploy is True:
return True, list()
+ if not ignore_deployed and contract_version is not None:
+ contract_version, _data = self.blockchain.find_raw_contract_data(contract_name=self.contract_name,
+ requested_version=contract_version)
+
rules = [
- (self.is_deployed is not True, 'Contract already deployed'),
+ (ignore_deployed or self.is_deployed(contract_version) is not True, 'Contract already deployed'),
(self.deployer_address is not None, 'No deployer address set.'),
(self.deployer_address is not NO_DEPLOYER_CONFIGURED, 'No deployer address set.'),
]
@@ -154,7 +169,7 @@ class BaseContractDeployer:
raise self.ContractDeploymentError(message)
return True
- def deploy(self, gas_limit: int, progress) -> dict:
+ def deploy(self, gas_limit: int, progress, **overrides) -> dict:
"""
Provides for the setup, deployment, and initialization of ethereum smart contracts.
Emits the configured blockchain network transactions for single contract instance publication.
@@ -165,12 +180,12 @@ class BaseContractDeployer:
agent = self.agency(registry=self.registry, contract=self._contract)
return agent
- def get_latest_enrollment(self, registry: BaseContractRegistry) -> Contract:
+ def get_latest_enrollment(self, registry: BaseContractRegistry) -> VersionedContract:
"""Get the latest enrolled version of the contract from the registry."""
- contract = self.blockchain.get_contract_by_name(name=self.contract_name,
+ contract = self.blockchain.get_contract_by_name(contract_name=self.contract_name,
registry=registry,
use_proxy_address=False,
- version='latest')
+ enrollment_version='latest')
return contract
@@ -223,7 +238,14 @@ class UpgradeableContractMixin:
class ContractNotUpgradeable(RuntimeError):
pass
- def deploy(self, secret_hash: bytes, initial_deployment: bool = True, gas_limit: int = None, progress = None) -> dict:
+ def deploy(self,
+ secret_hash: bytes,
+ initial_deployment: bool = True,
+ gas_limit: int = None,
+ progress=None,
+ contract_version: str = "latest",
+ ignore_deployed: bool = False
+ ) -> dict:
"""
Provides for the setup, deployment, and initialization of ethereum smart contracts.
Emits the configured blockchain network transactions for single contract instance publication.
@@ -232,7 +254,7 @@ class UpgradeableContractMixin:
raise self.ContractNotUpgradeable(f"{self.contract_name} is not upgradeable.")
raise NotImplementedError
- def get_principal_contract(self, registry: BaseContractRegistry, provider_uri: str = None) -> Contract:
+ def get_principal_contract(self, registry: BaseContractRegistry, provider_uri: str = None) -> VersionedContract:
"""
Get the on-chain targeted version of the principal contract directly
without assembling it with its proxy.
@@ -240,13 +262,13 @@ class UpgradeableContractMixin:
if not self._upgradeable:
raise self.ContractNotUpgradeable(f"{self.contract_name} is not upgradeable.")
blockchain = BlockchainInterfaceFactory.get_interface(provider_uri=provider_uri)
- principal_contract = blockchain.get_contract_by_name(name=self.contract_name,
+ principal_contract = blockchain.get_contract_by_name(contract_name=self.contract_name,
registry=registry,
proxy_name=self._proxy_deployer.contract_name,
use_proxy_address=False)
return principal_contract
- def get_proxy_contract(self, registry: BaseContractRegistry, provider_uri: str = None) -> Contract:
+ def get_proxy_contract(self, registry: BaseContractRegistry, provider_uri: str = None) -> VersionedContract:
if not self._upgradeable:
raise cls.ContractNotUpgradeable(f"{self.contract_name} is not upgradeable.")
blockchain = BlockchainInterfaceFactory.get_interface(provider_uri=provider_uri)
@@ -271,7 +293,8 @@ class UpgradeableContractMixin:
target_address: str,
existing_secret_plaintext: bytes,
new_secret_hash: bytes,
- gas_limit: int = None):
+ gas_limit: int = None,
+ version: str = "latest"):
"""
Directly engage a proxy contract for an existing deployment, executing the proxy's
upgrade interfaces to verify upgradeability and modify the on-chain contract target.
@@ -291,7 +314,13 @@ class UpgradeableContractMixin:
gas_limit=gas_limit)
return receipt
- def upgrade(self, existing_secret_plaintext: bytes, new_secret_hash: bytes, gas_limit: int = None):
+ def upgrade(self,
+ existing_secret_plaintext: bytes,
+ new_secret_hash: bytes,
+ gas_limit: int = None,
+ contract_version: str = "latest",
+ ignore_deployed: bool = False,
+ **overrides):
"""
Deploy a new version of a contract, then engage the proxy contract's upgrade interfaces.
"""
@@ -299,14 +328,16 @@ class UpgradeableContractMixin:
# 1 - Raise if not all-systems-go #
if not self._upgradeable:
raise self.ContractNotUpgradeable(f"{self.contract_name} is not upgradeable.")
- self.check_deployment_readiness()
+ self.check_deployment_readiness(contract_version=contract_version, ignore_deployed=ignore_deployed)
# 2 - Get Bare Contracts
existing_bare_contract = self.get_principal_contract(registry=self.registry, provider_uri=self.blockchain.provider_uri)
proxy_deployer = self.get_proxy_deployer(registry=self.registry, provider_uri=self.blockchain.provider_uri)
# 3 - Deploy new version
- new_contract, deploy_receipt = self._deploy_essential(gas_limit=gas_limit)
+ new_contract, deploy_receipt = self._deploy_essential(contract_version=contract_version,
+ gas_limit=gas_limit,
+ **overrides)
# 4 - Wrap the escrow contract
wrapped_contract = self.blockchain._wrap_contract(wrapper_contract=proxy_deployer.contract,
@@ -333,7 +364,7 @@ class UpgradeableContractMixin:
raise self.ContractNotUpgradeable(f"{self.contract_name} is not upgradeable.")
existing_bare_contract = self.blockchain.get_contract_by_name(registry=self.registry,
- name=self.contract_name,
+ contract_name=self.contract_name,
proxy_name=self._proxy_deployer.contract_name,
use_proxy_address=False)
proxy_deployer = self.get_proxy_deployer(registry=self.registry, provider_uri=self.blockchain.provider_uri)
@@ -361,7 +392,7 @@ class NucypherTokenDeployer(BaseContractDeployer):
_upgradeable = False
_ownable = False
- def deploy(self, gas_limit: int = None, progress=None) -> dict:
+ def deploy(self, gas_limit: int = None, progress=None, **overrides) -> dict:
"""
Deploy and publish the NuCypher Token contract
to the blockchain network specified in self.blockchain.network.
@@ -371,11 +402,14 @@ class NucypherTokenDeployer(BaseContractDeployer):
self.check_deployment_readiness()
# Order-sensitive!
+ constructor_kwargs = {"_totalSupply": self.economics.erc20_total_supply}
+ constructor_kwargs.update(overrides)
+ constructor_kwargs = {k: v for k, v in constructor_kwargs.items() if v is not None}
contract, deployment_receipt = self.blockchain.deploy_contract(self.deployer_address,
self.registry,
self.contract_name,
gas_limit=gas_limit,
- _totalSupply=self.economics.erc20_total_supply)
+ **constructor_kwargs)
if progress:
progress.update(1)
self._contract = contract
@@ -458,21 +492,36 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
token_contract_name = NucypherTokenDeployer.contract_name
self.token_contract = self.blockchain.get_contract_by_name(registry=self.registry,
- name=token_contract_name)
+ contract_name=token_contract_name)
def __check_policy_manager(self):
result = self.contract.functions.policyManager().call()
if result == self.blockchain.NULL_ADDRESS:
raise RuntimeError("PolicyManager contract is not initialized.")
- def _deploy_essential(self, gas_limit: int = None):
- escrow_constructor_args = (self.token_contract.address, *self.economics.staking_deployment_parameters)
+ def _deploy_essential(self, contract_version: str, gas_limit: int = None, **overrides):
+ args = self.economics.staking_deployment_parameters
+ constructor_kwargs = {
+ "_hoursPerPeriod": args[0],
+ "_miningCoefficient": args[1],
+ "_lockedPeriodsCoefficient": args[2],
+ "_rewardedPeriods": args[3],
+ "_minLockedPeriods": args[4],
+ "_minAllowableLockedTokens": args[5],
+ "_maxAllowableLockedTokens": args[6],
+ "_minWorkerPeriods": args[7]
+ }
+ constructor_kwargs.update(overrides)
+ constructor_kwargs = {k: v for k, v in constructor_kwargs.items() if v is not None}
+ # Force use of the token address from the registry
+ constructor_kwargs.update({"_token": self.token_contract.address})
the_escrow_contract, deploy_receipt = self.blockchain.deploy_contract(
self.deployer_address,
self.registry,
self.contract_name,
gas_limit=gas_limit,
- *escrow_constructor_args,
+ contract_version=contract_version,
+ **constructor_kwargs
)
return the_escrow_contract, deploy_receipt
@@ -481,7 +530,10 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
initial_deployment: bool = True,
secret_hash: bytes = None,
gas_limit: int = None,
- progress=None
+ progress=None,
+ contract_version: str = "latest",
+ ignore_deployed: bool = False,
+ **overrides
) -> dict:
"""
Deploy and publish the StakingEscrow contract
@@ -503,7 +555,7 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
f" deployment series for {self.contract_name}.")
# Raise if not all-systems-go
- self.check_deployment_readiness()
+ self.check_deployment_readiness(contract_version=contract_version, ignore_deployed=ignore_deployed)
# Build deployment arguments
origin_args = {}
@@ -511,7 +563,9 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
origin_args.update({'gas': gas_limit})
# 1 - Deploy #
- the_escrow_contract, deploy_receipt = self._deploy_essential(gas_limit=gas_limit)
+ the_escrow_contract, deploy_receipt = self._deploy_essential(contract_version=contract_version,
+ gas_limit=gas_limit,
+ **overrides)
# This is the end of bare deployment.
if not initial_deployment:
@@ -583,38 +637,42 @@ class PolicyManagerDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
deployment_steps = ('deployment', 'dispatcher_deployment', 'set_policy_manager')
_proxy_deployer = DispatcherDeployer
-
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
proxy_name = StakingEscrowDeployer._proxy_deployer.contract_name
staking_contract_name = StakingEscrowDeployer.contract_name
self.staking_contract = self.blockchain.get_contract_by_name(registry=self.registry,
- name=staking_contract_name,
+ contract_name=staking_contract_name,
proxy_name=proxy_name)
- def _deploy_essential(self, gas_limit: int = None) -> tuple:
+ def _deploy_essential(self, contract_version: str, gas_limit: int = None) -> tuple:
+ constructor_kwargs = {"_escrow": self.staking_contract.address}
policy_manager_contract, deploy_receipt = self.blockchain.deploy_contract(self.deployer_address,
self.registry,
self.contract_name,
- self.staking_contract.address,
- gas_limit=gas_limit)
+ gas_limit=gas_limit,
+ contract_version=contract_version,
+ **constructor_kwargs)
return policy_manager_contract, deploy_receipt
def deploy(self,
initial_deployment: bool = True,
secret_hash: bytes = None,
gas_limit: int = None,
- progress=None
+ progress=None,
+ contract_version: str = "latest",
+ ignore_deployed: bool = False
) -> Dict[str, dict]:
if initial_deployment and not secret_hash:
raise ValueError(f"An upgrade secret hash is required to perform an initial"
f" deployment series for {self.contract_name}.")
- self.check_deployment_readiness()
+ self.check_deployment_readiness(contract_version=contract_version, ignore_deployed=ignore_deployed)
# Creator deploys the policy manager
- policy_manager_contract, deploy_receipt = self._deploy_essential(gas_limit=gas_limit)
+ policy_manager_contract, deploy_receipt = self._deploy_essential(contract_version=contract_version,
+ gas_limit=gas_limit)
# This is the end of bare deployment.
if not initial_deployment:
@@ -718,21 +776,21 @@ class StakingInterfaceDeployer(BaseContractDeployer, UpgradeableContractMixin):
token_contract_name = NucypherTokenDeployer.contract_name
self.token_contract = self.blockchain.get_contract_by_name(registry=self.registry,
- name=token_contract_name)
+ contract_name=token_contract_name)
staking_contract_name = StakingEscrowDeployer.contract_name
staking_proxy_name = StakingEscrowDeployer._proxy_deployer.contract_name
self.staking_contract = self.blockchain.get_contract_by_name(registry=self.registry,
- name=staking_contract_name,
+ contract_name=staking_contract_name,
proxy_name=staking_proxy_name)
policy_contract_name = PolicyManagerDeployer.contract_name
policy_proxy_name = PolicyManagerDeployer._proxy_deployer.contract_name
self.policy_contract = self.blockchain.get_contract_by_name(registry=self.registry,
- name=policy_contract_name,
+ contract_name=policy_contract_name,
proxy_name=policy_proxy_name)
- def _deploy_essential(self, gas_limit: int = None):
+ def _deploy_essential(self, contract_version: str, gas_limit: int = None):
"""Note: These parameters are order-sensitive"""
constructor_args = (self.token_contract.address,
self.staking_contract.address,
@@ -742,14 +800,17 @@ class StakingInterfaceDeployer(BaseContractDeployer, UpgradeableContractMixin):
self.registry,
self.contract_name,
*constructor_args,
- gas_limit=gas_limit)
+ gas_limit=gas_limit,
+ contract_version=contract_version)
return contract, deployment_receipt
def deploy(self,
initial_deployment: bool = True,
secret_hash: bytes = None,
gas_limit: int = None,
- progress=None
+ progress=None,
+ contract_version: str = "latest",
+ ignore_deployed: bool = False
) -> dict:
"""
Deploys a new StakingInterface contract, and a new StakingInterfaceRouter, targeting the former.
@@ -759,9 +820,11 @@ class StakingInterfaceDeployer(BaseContractDeployer, UpgradeableContractMixin):
if initial_deployment and not secret_hash:
raise ValueError(f"An upgrade secret hash is required to perform an initial"
f" deployment series for {self.contract_name}.")
+ self.check_deployment_readiness(contract_version=contract_version, ignore_deployed=ignore_deployed)
# 1 - StakingInterface
- staking_interface_contract, deployment_receipt = self._deploy_essential(gas_limit=gas_limit)
+ staking_interface_contract, deployment_receipt = self._deploy_essential(contract_version=contract_version,
+ gas_limit=gas_limit)
# This is the end of bare deployment.
if not initial_deployment:
@@ -802,10 +865,10 @@ class PreallocationEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin
def __init__(self, allocation_registry: AllocationRegistry = None, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.token_contract = self.blockchain.get_contract_by_name(registry=self.registry,
- name=NucypherTokenDeployer.contract_name)
+ contract_name=NucypherTokenDeployer.contract_name)
dispatcher_name = StakingEscrowDeployer._proxy_deployer.contract_name
self.staking_escrow_contract = self.blockchain.get_contract_by_name(registry=self.registry,
- name=StakingEscrowDeployer.contract_name,
+ contract_name=StakingEscrowDeployer.contract_name,
proxy_name=dispatcher_name)
self.__beneficiary_address = NO_BENEFICIARY
self.__allocation_registry = allocation_registry or self.__allocation_registry()
@@ -887,7 +950,7 @@ class PreallocationEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin
"""Deploy a new instance of PreallocationEscrow to the blockchain."""
self.check_deployment_readiness()
router_contract = self.blockchain.get_contract_by_name(registry=self.registry,
- name=self._router_deployer.contract_name)
+ contract_name=self._router_deployer.contract_name)
args = (self.deployer_address,
self.registry,
self.contract_name,
@@ -923,32 +986,48 @@ class AdjudicatorDeployer(BaseContractDeployer, UpgradeableContractMixin, Ownabl
staking_contract_name = StakingEscrowDeployer.contract_name
proxy_name = StakingEscrowDeployer._proxy_deployer.contract_name
self.staking_contract = self.blockchain.get_contract_by_name(registry=self.registry,
- name=staking_contract_name,
+ contract_name=staking_contract_name,
proxy_name=proxy_name)
- def _deploy_essential(self, gas_limit: int = None):
- constructor_args = (self.staking_contract.address,
- *self.economics.slashing_deployment_parameters)
+ def _deploy_essential(self, contract_version: str, gas_limit: int = None, **overrides):
+ args = self.economics.slashing_deployment_parameters
+ constructor_kwargs = {
+ "_hashAlgorithm": args[0],
+ "_basePenalty": args[1],
+ "_penaltyHistoryCoefficient": args[2],
+ "_percentagePenaltyCoefficient": args[3],
+ "_rewardCoefficient": args[4]
+ }
+ constructor_kwargs.update(overrides)
+ constructor_kwargs = {k: v for k, v in constructor_kwargs.items() if v is not None}
+ # Force use of the escrow address from the registry
+ constructor_kwargs.update({"_escrow": self.staking_contract.address})
adjudicator_contract, deploy_receipt = self.blockchain.deploy_contract(self.deployer_address,
self.registry,
self.contract_name,
- *constructor_args,
- gas_limit=gas_limit)
+ gas_limit=gas_limit,
+ contract_version=contract_version,
+ **constructor_kwargs)
return adjudicator_contract, deploy_receipt
def deploy(self,
initial_deployment: bool = True,
secret_hash: bytes = None,
gas_limit: int = None,
- progress=None) -> Dict[str, str]:
+ progress=None,
+ contract_version: str = "latest",
+ ignore_deployed: bool = False,
+ **overrides) -> Dict[str, str]:
if initial_deployment and not secret_hash:
raise ValueError(f"An upgrade secret hash is required to perform an initial"
f" deployment series for {self.contract_name}.")
- self.check_deployment_readiness()
+ self.check_deployment_readiness(contract_version=contract_version, ignore_deployed=ignore_deployed)
- adjudicator_contract, deploy_receipt = self._deploy_essential(gas_limit=gas_limit)
+ adjudicator_contract, deploy_receipt = self._deploy_essential(contract_version=contract_version,
+ gas_limit=gas_limit,
+ **overrides)
# This is the end of bare deployment.
if not initial_deployment:
diff --git a/nucypher/blockchain/eth/interfaces.py b/nucypher/blockchain/eth/interfaces.py
index 7f702abb3..fd35c1cec 100644
--- a/nucypher/blockchain/eth/interfaces.py
+++ b/nucypher/blockchain/eth/interfaces.py
@@ -37,8 +37,7 @@ from eth_tester import EthereumTester
from eth_utils import to_checksum_address, is_checksum_address
from twisted.logger import Logger
from web3 import Web3, WebsocketProvider, HTTPProvider, IPCProvider
-from web3.contract import Contract
-from web3.contract import ContractConstructor
+from web3.contract import ContractConstructor, Contract
from web3.contract import ContractFunction
from web3.exceptions import TimeExhausted
from web3.exceptions import ValidationError
@@ -59,11 +58,14 @@ from nucypher.blockchain.eth.providers import (
from nucypher.blockchain.eth.registry import BaseContractRegistry
from nucypher.blockchain.eth.sol.compile import SolidityCompiler
from nucypher.characters.control.emitters import StdoutEmitter
-from nucypher.utilities.logging import console_observer, GlobalLoggerSettings
Web3Providers = Union[IPCProvider, WebsocketProvider, HTTPProvider, EthereumTester]
+class VersionedContract(Contract):
+ version = None
+
+
class BlockchainInterface:
"""
Interacts with a solidity compiler and a registry in order to instantiate compiled
@@ -76,7 +78,7 @@ class BlockchainInterface:
process = NO_PROVIDER_PROCESS.bool_value(False)
Web3 = Web3
- _contract_factory = Contract
+ _contract_factory = VersionedContract
class InterfaceError(Exception):
pass
@@ -431,20 +433,21 @@ class BlockchainInterface:
def get_contract_by_name(self,
registry: BaseContractRegistry,
- name: str,
- version: int = None,
+ contract_name: str,
+ contract_version: str = None,
+ enrollment_version: Union[int, str] = None,
proxy_name: str = None,
use_proxy_address: bool = True
- ) -> Union[Contract, List[tuple]]:
+ ) -> Union[VersionedContract, List[tuple]]:
"""
Instantiate a deployed contract from registry data,
and assimilate it with its proxy if it is upgradeable,
or return all registered records if use_proxy_address is False.
"""
- target_contract_records = registry.search(contract_name=name)
+ target_contract_records = registry.search(contract_name=contract_name, contract_version=contract_version)
if not target_contract_records:
- raise self.UnknownContract(f"No such contract records with name {name}.")
+ raise self.UnknownContract(f"No such contract records with name {contract_name}:{contract_version}.")
if proxy_name:
@@ -452,61 +455,69 @@ class BlockchainInterface:
proxy_records = registry.search(contract_name=proxy_name)
results = list()
- for proxy_name, proxy_addr, proxy_abi in proxy_records:
+ for proxy_name, proxy_version, proxy_address, proxy_abi in proxy_records:
proxy_contract = self.client.w3.eth.contract(abi=proxy_abi,
- address=proxy_addr,
+ address=proxy_address,
+ version=proxy_version,
ContractFactoryClass=self._contract_factory)
# Read this dispatcher's target address from the blockchain
proxy_live_target_address = proxy_contract.functions.target().call()
- for target_name, target_addr, target_abi in target_contract_records:
+ for target_name, target_version, target_address, target_abi in target_contract_records:
- if target_addr == proxy_live_target_address:
+ if target_address == proxy_live_target_address:
if use_proxy_address:
- pair = (proxy_addr, target_abi)
+ triplet = (proxy_address, target_version, target_abi)
else:
- pair = (target_addr, target_abi)
+ triplet = (target_address, target_version, target_abi)
else:
continue
- results.append(pair)
+ results.append(triplet)
if len(results) > 1:
- address, abi = results[0]
+ address, _version, _abi = results[0]
message = "Multiple {} deployments are targeting {}".format(proxy_name, address)
- raise self.InterfaceError(message.format(name))
+ raise self.InterfaceError(message.format(contract_name))
else:
try:
- selected_address, selected_abi = results[0]
+ selected_address, selected_version, selected_abi = results[0]
except IndexError:
- raise self.UnknownContract(f"There are no Dispatcher records targeting '{name}'")
+ raise self.UnknownContract(
+ f"There are no Dispatcher records targeting '{contract_name}':{contract_version}")
else:
# NOTE: 0 must be allowed as a valid version number
if len(target_contract_records) != 1:
- if version is None:
- m = f"{len(target_contract_records)} records enrolled for contract {name} " \
+ if enrollment_version is None:
+ m = f"{len(target_contract_records)} records enrolled " \
+ f"for contract {contract_name}:{contract_version} " \
f"and no version index was supplied."
raise self.InterfaceError(m)
- version = self.__get_version_index(name=name,
- version_index=version,
- enrollments=len(target_contract_records))
+ enrollment_version = self.__get_enrollment_version_index(name=contract_name,
+ contract_version=contract_version,
+ version_index=enrollment_version,
+ enrollments=len(target_contract_records))
else:
- version = -1 # default
+ enrollment_version = -1 # default
- _target_contract_name, selected_address, selected_abi = target_contract_records[version]
+ _contract_name, selected_version, selected_address, selected_abi = target_contract_records[enrollment_version]
# Create the contract from selected sources
unified_contract = self.client.w3.eth.contract(abi=selected_abi,
address=selected_address,
+ version=selected_version,
ContractFactoryClass=self._contract_factory)
return unified_contract
@staticmethod
- def __get_version_index(version_index: Union[int, str], enrollments: int, name: str):
+ def __get_enrollment_version_index(version_index: Union[int, str],
+ enrollments: int,
+ name: str,
+ contract_version: str):
version_names = {'latest': -1, 'earliest': 0}
try:
version = version_names[version_index]
@@ -515,10 +526,11 @@ class BlockchainInterface:
version = int(version_index)
except ValueError:
what_is_this = version_index
- raise ValueError(f"'{what_is_this}' is not a valid version number")
+ raise ValueError(f"'{what_is_this}' is not a valid enrollment version number")
else:
if version > enrollments - 1:
- message = f"Version index '{version}' is larger than the number of enrollments for {name}."
+ message = f"Version index '{version}' is larger than the number of enrollments " \
+ f"for {name}:{contract_version}."
raise ValueError(message)
return version
@@ -526,7 +538,7 @@ class BlockchainInterface:
class BlockchainDeployerInterface(BlockchainInterface):
TIMEOUT = 600 # seconds
- _contract_factory = Contract
+ _contract_factory = VersionedContract
class NoDeployerAddress(RuntimeError):
pass
@@ -544,18 +556,13 @@ class BlockchainDeployerInterface(BlockchainInterface):
return self.is_connected
def _setup_solidity(self, compiler: SolidityCompiler = None):
-
- # if a SolidityCompiler class instance was passed,
- # compile from solidity source code.
- self.__sol_compiler = compiler
if compiler:
# Execute the compilation if we're recompiling
# Otherwise read compiled contract data from the registry.
- interfaces = self.__sol_compiler.compile()
- __raw_contract_cache = interfaces
+ _raw_contract_cache = compiler.compile()
else:
- __raw_contract_cache = NO_COMPILATION_PERFORMED
- self.__raw_contract_cache = __raw_contract_cache
+ _raw_contract_cache = NO_COMPILATION_PERFORMED
+ self._raw_contract_cache = _raw_contract_cache
@validate_checksum_address
def deploy_contract(self,
@@ -565,8 +572,9 @@ class BlockchainDeployerInterface(BlockchainInterface):
*constructor_args,
enroll: bool = True,
gas_limit: int = None,
+ contract_version: str = 'latest',
**constructor_kwargs
- ) -> Tuple[Contract, dict]:
+ ) -> Tuple[VersionedContract, dict]:
"""
Retrieve compiled interface data from the cache and
return an instantiated deployed contract
@@ -585,11 +593,12 @@ class BlockchainDeployerInterface(BlockchainInterface):
pprint_args = str(tuple(constructor_args))
pprint_args = pprint_args.replace("{", "{{").replace("}", "}}") # See #724
- self.log.info(f"Deploying contract {contract_name} with "
+
+ contract_factory = self.get_contract_factory(contract_name=contract_name, version=contract_version)
+ self.log.info(f"Deploying contract {contract_name}:{contract_factory.version} with "
f"deployer address {deployer_address} "
f"and parameters {pprint_args}")
- contract_factory = self.get_contract_factory(contract_name=contract_name)
transaction_function = contract_factory.constructor(*constructor_args, **constructor_kwargs)
#
@@ -606,39 +615,74 @@ class BlockchainDeployerInterface(BlockchainInterface):
# Success
address = receipt['contractAddress']
- self.log.info(f"Confirmed {contract_name} deployment: new address {address}")
+ self.log.info(f"Confirmed {contract_name}:{contract_factory.version} deployment: new address {address}")
#
# Instantiate & Enroll contract
#
- contract = self.client.w3.eth.contract(address=address, abi=contract_factory.abi)
+ contract = self.client.w3.eth.contract(address=address,
+ abi=contract_factory.abi,
+ version=contract_factory.version,
+ ContractFactoryClass=self._contract_factory)
if enroll is True:
registry.enroll(contract_name=contract_name,
contract_address=contract.address,
- contract_abi=contract_factory.abi)
+ contract_abi=contract.abi,
+ contract_version=contract.version)
return contract, receipt # receipt
- def get_contract_factory(self, contract_name: str) -> Contract:
- """Retrieve compiled interface data from the cache and return web3 contract"""
+ def find_raw_contract_data(self, contract_name: str, requested_version: str = 'latest') -> Tuple[str, dict]:
try:
- interface = self.__raw_contract_cache[contract_name]
+ contract_data = self._raw_contract_cache[contract_name]
except KeyError:
raise self.UnknownContract('{} is not a locally compiled contract.'.format(contract_name))
except TypeError:
- if self.__raw_contract_cache is NO_COMPILATION_PERFORMED:
+ if self._raw_contract_cache is NO_COMPILATION_PERFORMED:
message = "The local contract compiler cache is empty because no compilation was performed."
raise self.InterfaceError(message)
raise
- else:
- contract = self.client.w3.eth.contract(abi=interface['abi'],
- bytecode=interface['bin'],
- ContractFactoryClass=Contract)
- return contract
- def _wrap_contract(self, wrapper_contract: Contract, target_contract: Contract) -> Contract:
+ try:
+ return requested_version, contract_data[requested_version]
+ except KeyError:
+ if requested_version != 'latest' and requested_version != 'earliest':
+ raise self.UnknownContract('Version {} of contract {} is not a locally compiled. '
+ 'Available versions: {}'
+ .format(requested_version, contract_name, contract_data.keys()))
+
+ if len(contract_data.keys()) == 1:
+ return next(iter(contract_data.items()))
+
+ # Get the latest or the earliest versions
+ current_version_parsed = (-1, -1, -1)
+ current_version = None
+ current_data = None
+ for version, data in contract_data.items():
+ major, minor, patch = [int(v) for v in version[1:].split(".", 3)]
+ if current_version_parsed[0] == -1 or \
+ requested_version == 'latest' and (major, minor, patch) > current_version_parsed or \
+ requested_version == 'earliest' and (major, minor, patch) < current_version_parsed:
+ current_version_parsed = (major, minor, patch)
+ current_data = data
+ current_version = version
+ return current_version, current_data
+
+ def get_contract_factory(self, contract_name: str, version: str = 'latest') -> VersionedContract:
+ """Retrieve compiled interface data from the cache and return web3 contract"""
+ version, interface = self.find_raw_contract_data(contract_name, version)
+ contract = self.client.w3.eth.contract(abi=interface['abi'],
+ bytecode=interface['bin'],
+ version=version,
+ ContractFactoryClass=self._contract_factory)
+ return contract
+
+ def _wrap_contract(self,
+ wrapper_contract: VersionedContract,
+ target_contract: VersionedContract
+ ) -> VersionedContract:
"""
Used for upgradeable contracts; Returns a new contract object assembled
with its own address but the abi of the other.
@@ -647,6 +691,7 @@ class BlockchainDeployerInterface(BlockchainInterface):
# Wrap the contract
wrapped_contract = self.client.w3.eth.contract(abi=target_contract.abi,
address=wrapper_contract.address,
+ version=target_contract.version,
ContractFactoryClass=self._contract_factory)
return wrapped_contract
@@ -654,15 +699,16 @@ class BlockchainDeployerInterface(BlockchainInterface):
def get_proxy_contract(self,
registry: BaseContractRegistry,
target_address: str,
- proxy_name: str) -> Contract:
+ proxy_name: str) -> VersionedContract:
# Lookup proxies; Search for a registered proxy that targets this contract record
records = registry.search(contract_name=proxy_name)
dispatchers = list()
- for name, addr, abi in records:
+ for name, version, address, abi in records:
proxy_contract = self.client.w3.eth.contract(abi=abi,
- address=addr,
+ address=address,
+ version=version,
ContractFactoryClass=self._contract_factory)
# Read this dispatchers target address from the blockchain
diff --git a/nucypher/blockchain/eth/registry.py b/nucypher/blockchain/eth/registry.py
index 7e42b2f9b..8366b9bec 100644
--- a/nucypher/blockchain/eth/registry.py
+++ b/nucypher/blockchain/eth/registry.py
@@ -282,7 +282,7 @@ class BaseContractRegistry(ABC):
entries = iter(record[1] for record in self.read())
return entries
- def enroll(self, contract_name, contract_address, contract_abi) -> None:
+ def enroll(self, contract_name, contract_address, contract_abi, contract_version) -> None:
"""
Enrolls a contract to the chain registry by writing the name, address,
and abi information to the filesystem as JSON.
@@ -290,32 +290,42 @@ class BaseContractRegistry(ABC):
Note: Unless you are developing NuCypher, you most likely won't ever
need to use this.
"""
- contract_data = [contract_name, contract_address, contract_abi]
+ contract_data = [contract_name, contract_version, contract_address, contract_abi]
try:
registry_data = self.read()
except self.RegistryError:
- self.log.info("Blank registry encountered: enrolling {}:{}".format(contract_name, contract_address))
+ self.log.info("Blank registry encountered: enrolling {}:{}:{}"
+ .format(contract_name, contract_version, contract_address))
registry_data = list() # empty registry
registry_data.append(contract_data)
self.write(registry_data)
- self.log.info("Enrolled {}:{} into registry.".format(contract_name, contract_address))
+ self.log.info("Enrolled {}:{}:{} into registry.".format(contract_name, contract_version, contract_address))
- def search(self, contract_name: str = None, contract_address: str = None) -> tuple:
+ def search(self, contract_name: str = None, contract_version: str = None, contract_address: str = None) -> tuple:
"""
Searches the registry for a contract with the provided name or address
and returns the contracts component data.
"""
if not (bool(contract_name) ^ bool(contract_address)):
raise ValueError("Pass contract_name or contract_address, not both.")
+ if bool(contract_version) and not bool(contract_name):
+ raise ValueError("Pass contract_version together with contract_name.")
contracts = list()
registry_data = self.read()
try:
- for name, addr, abi in registry_data:
- if contract_name == name or contract_address == addr:
- contracts.append((name, addr, abi))
+ for contract in registry_data:
+ if len(contract) == 3:
+ name, address, abi = contract
+ version = None
+ else:
+ name, version, address, abi = contract
+ if contract_name == name and \
+ (contract_version is None or version == contract_version) or \
+ contract_address == address:
+ contracts.append((name, version, address, abi))
except ValueError:
message = "Missing or corrupted registry data"
self.log.critical(message)
diff --git a/nucypher/blockchain/eth/sol/compile.py b/nucypher/blockchain/eth/sol/compile.py
index 4f92dcd20..9e9a545e6 100644
--- a/nucypher/blockchain/eth/sol/compile.py
+++ b/nucypher/blockchain/eth/sol/compile.py
@@ -14,9 +14,10 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see .
"""
-
-
+import collections
import os
+import re
+from typing import List, Set, Tuple
import sys
from twisted.logger import Logger
@@ -32,10 +33,16 @@ except ImportError:
# TODO: Issue #461 and #758 & PR #1480 - Include precompiled ABI; Do not use py-solc in standard installation
pass
+SourceDirs = collections.namedtuple('SourceDirs', ['root_source_dir', # type: str
+ 'other_source_dirs', # type: Set[str]
+ ])
+SourceDirs.__new__.__defaults__ = (None,)
+
class SolidityCompiler:
- __default_version = 'v0.5.9'
+ __default_compiler_version = 'v0.5.9'
+ __default_contract_version = 'v0.0.0'
__default_configuration_path = os.path.join(dirname(abspath(__file__)), './compiler.json')
__default_sol_binary_path = shutil.which('solc')
@@ -43,24 +50,35 @@ class SolidityCompiler:
__bin_path = os.path.dirname(sys.executable) # type: str
__default_sol_binary_path = os.path.join(__bin_path, 'solc') # type: str
- __default_contract_dir = os.path.join(dirname(abspath(__file__)), 'source', 'contracts')
+ __default_contract_dir = os.path.join(dirname(abspath(__file__)), 'source')
__default_chain_name = 'tester'
+ __compiled_contracts_dir = 'contracts'
+ __zeppelin_library_dir = 'zeppelin'
+
optimization_runs = 200
+ class CompilerError(Exception):
+ pass
+
+ @classmethod
+ def default_contract_dir(cls):
+ return cls.__default_contract_dir
+
def __init__(self,
solc_binary_path: str = None,
configuration_path: str = None,
chain_name: str = None,
- source_dir: str = None,
- test_contract_dir: str = None
+ source_dirs: List[SourceDirs] = None
) -> None:
-
+
self.log = Logger('solidity-compiler')
# Compiler binary and root solidity source code directory
self.__sol_binary_path = solc_binary_path if solc_binary_path is not None else self.__default_sol_binary_path
- self.source_dir = source_dir if source_dir is not None else self.__default_contract_dir
- self._test_solidity_source_dir = test_contract_dir
+ if source_dirs is None or len(source_dirs) == 0:
+ self.source_dirs = [SourceDirs(root_source_dir=self.__default_contract_dir)]
+ else:
+ self.source_dirs = source_dirs
# JSON config
self.__configuration_path = configuration_path if configuration_path is not None else self.__default_configuration_path
@@ -74,20 +92,58 @@ class SolidityCompiler:
Installs the specified solidity compiler version.
https://github.com/ethereum/py-solc#installing-the-solc-binary
"""
- version = version if version is not None else self.__default_version
+ version = version if version is not None else self.__default_compiler_version
return install_solc(version, platform=None) # TODO: #1478 - Implement or remove this
def compile(self) -> dict:
+ interfaces = dict()
+ for root_source_dir, other_source_dirs in self.source_dirs:
+ if root_source_dir is None:
+ self.log.warn("One of the root directories is None")
+ continue
+
+ raw_interfaces = self._compile(root_source_dir, other_source_dirs)
+ for name, data in raw_interfaces.items():
+ # Extract contract version from docs
+ version_search = re.search(r"""
+
+ \"details\": # @dev tag in contract docs
+ \".*? # Skip any data in the beginning of details
+ \| # Beginning of version definition |
+ (v # Capture version starting from symbol v
+ \d+ # At least one digit of major version
+ \. # Digits splitter
+ \d+ # At least one digit of minor version
+ \. # Digits splitter
+ \d+ # At least one digit of patch
+ ) # End of capturing
+ \| # End of version definition |
+ .*?\" # Skip any data in the end of details
+
+ """, data['devdoc'], re.VERBOSE)
+ version = version_search.group(1) if version_search else self.__default_contract_version
+ try:
+ existence_data = interfaces[name]
+ except KeyError:
+ existence_data = dict()
+ interfaces.update({name: existence_data})
+ if version not in existence_data:
+ existence_data.update({version: data})
+ return interfaces
+
+ def _compile(self, root_source_dir: str, other_source_dirs: [str]) -> dict:
"""Executes the compiler with parameters specified in the json config"""
self.log.info("Using solidity compiler binary at {}".format(self.__sol_binary_path))
- self.log.info("Compiling solidity source files at {}".format(self.source_dir))
+ contracts_dir = os.path.join(root_source_dir, self.__compiled_contracts_dir)
+ self.log.info("Compiling solidity source files at {}".format(contracts_dir))
source_paths = set()
- source_walker = os.walk(top=self.source_dir, topdown=True)
- if self._test_solidity_source_dir:
- test_source_walker = os.walk(top=self._test_solidity_source_dir, topdown=True)
- source_walker = itertools.chain(source_walker, test_source_walker)
+ source_walker = os.walk(top=contracts_dir, topdown=True)
+ if other_source_dirs is not None:
+ for source_dir in other_source_dirs:
+ other_source_walker = os.walk(top=source_dir, topdown=True)
+ source_walker = itertools.chain(source_walker, other_source_walker)
for root, dirs, files in source_walker:
for filename in files:
@@ -97,10 +153,10 @@ class SolidityCompiler:
self.log.debug("Collecting solidity source {}".format(path))
# Compile with remappings: https://github.com/ethereum/py-solc
- project_root = dirname(self.source_dir)
+ zeppelin_dir = os.path.join(root_source_dir, self.__zeppelin_library_dir)
- remappings = ("contracts={}".format(self.source_dir),
- "zeppelin={}".format(os.path.join(project_root, 'zeppelin')),
+ remappings = ("contracts={}".format(contracts_dir),
+ "zeppelin={}".format(zeppelin_dir),
)
self.log.info("Compiling with import remappings {}".format(", ".join(remappings)))
@@ -109,7 +165,7 @@ class SolidityCompiler:
try:
compiled_sol = compile_files(source_files=source_paths,
import_remappings=remappings,
- allow_paths=project_root,
+ allow_paths=root_source_dir,
optimize=True,
optimize_runs=optimization_runs)
diff --git a/nucypher/blockchain/eth/sol/source/contracts/Adjudicator.sol b/nucypher/blockchain/eth/sol/source/contracts/Adjudicator.sol
index 6208e6bb9..de1a16228 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/Adjudicator.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/Adjudicator.sol
@@ -10,7 +10,8 @@ import "zeppelin/math/Math.sol";
/**
* @notice Supervises stakers' behavior and punishes when something's wrong.
-**/
+* @dev |v1.1.1|
+*/
contract Adjudicator is Upgradeable {
using SafeMath for uint256;
@@ -47,7 +48,7 @@ contract Adjudicator is Upgradeable {
* @param _penaltyHistoryCoefficient Coefficient for calculating the penalty depending on the history
* @param _percentagePenaltyCoefficient Coefficient for calculating the percentage penalty
* @param _rewardCoefficient Coefficient for calculating the reward
- **/
+ */
constructor(
StakingEscrow _escrow,
SignatureVerifier.HashAlgorithm _hashAlgorithm,
@@ -81,7 +82,7 @@ contract Adjudicator is Upgradeable {
* @param _workerPublicKey Worker's signing public key, also known as "stamp"
* @param _workerIdentityEvidence Signature of worker's public key by worker's eth-key
* @param _preComputedData Additional pre-computed data for CFrag correctness verification
- **/
+ */
function evaluateCFrag(
bytes memory _capsuleBytes,
bytes memory _cFragBytes,
@@ -174,7 +175,7 @@ contract Adjudicator is Upgradeable {
* @notice Calculate penalty to the staker and reward to the investigator
* @param _staker Staker's address
* @param _stakerValue Amount of tokens that belong to the staker
- **/
+ */
function calculatePenaltyAndReward(address _staker, uint256 _stakerValue)
internal returns (uint256 penalty, uint256 reward)
{
diff --git a/nucypher/blockchain/eth/sol/source/contracts/Issuer.sol b/nucypher/blockchain/eth/sol/source/contracts/Issuer.sol
index dc8a3c17f..7fd2f7a5f 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/Issuer.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/Issuer.sol
@@ -10,7 +10,8 @@ import "contracts/lib/AdditionalMath.sol";
/**
* @notice Contract for calculate issued tokens
-**/
+* @dev |v1.1.2|
+*/
contract Issuer is Upgradeable {
using SafeMath for uint256;
using AdditionalMath for uint32;
@@ -32,7 +33,7 @@ contract Issuer is Upgradeable {
* supply for previous period (used in formula) and supply for current period which accumulates value
* before end of period. There is no order between them because of storage savings.
* So each time should check values of both variables.
- **/
+ */
uint256 public currentSupply1;
uint256 public currentSupply2;
@@ -46,7 +47,7 @@ contract Issuer is Upgradeable {
* @param _miningCoefficient Mining coefficient (k2)
* @param _lockedPeriodsCoefficient Locked periods coefficient (k1)
* @param _rewardedPeriods Max periods that will be additionally rewarded
- **/
+ */
constructor(
NuCypherToken _token,
uint32 _hoursPerPeriod,
@@ -79,7 +80,7 @@ contract Issuer is Upgradeable {
/**
* @dev Checks contract initialization
- **/
+ */
modifier isInitialized()
{
require(currentSupply1 != 0);
@@ -88,14 +89,14 @@ contract Issuer is Upgradeable {
/**
* @return Number of current period
- **/
+ */
function getCurrentPeriod() public view returns (uint16) {
return uint16(block.timestamp / secondsPerPeriod);
}
/**
* @notice Initialize reserved tokens for reward
- **/
+ */
function initialize() public onlyOwner {
require(currentSupply1 == 0);
currentMintingPeriod = getCurrentPeriod();
@@ -162,7 +163,7 @@ contract Issuer is Upgradeable {
/**
* @notice Return tokens for future minting
* @param _amount Amount of tokens
- **/
+ */
function unMint(uint256 _amount) internal {
currentSupply1 = currentSupply1 - _amount;
currentSupply2 = currentSupply2 - _amount;
@@ -170,7 +171,7 @@ contract Issuer is Upgradeable {
/**
* @notice Returns the number of tokens that can be mined
- **/
+ */
function getReservedReward() public view returns (uint256) {
return totalSupply - Math.max(currentSupply1, currentSupply2);
}
diff --git a/nucypher/blockchain/eth/sol/source/contracts/MultiSig.sol b/nucypher/blockchain/eth/sol/source/contracts/MultiSig.sol
index 89e7e2737..6354a6b5e 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/MultiSig.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/MultiSig.sol
@@ -6,7 +6,7 @@ import "zeppelin/math/SafeMath.sol";
/**
* @notice Multi-signature contract with off-chain signing
-**/
+*/
contract MultiSig {
using SafeMath for uint256;
@@ -33,7 +33,7 @@ contract MultiSig {
/**
* @param _required Number of required signings
* @param _owners List of initial owners.
- **/
+ */
constructor (uint8 _required, address[] memory _owners) public {
require(_owners.length <= MAX_OWNER_COUNT &&
_required <= _owners.length &&
@@ -56,7 +56,7 @@ contract MultiSig {
* @param _value Amount of ETH to transfer
* @param _data Call data
* @param _nonce Nonce
- **/
+ */
function getUnsignedTransactionHash(
address _sender,
address _destination,
@@ -78,7 +78,7 @@ contract MultiSig {
* @param _destination Destination address
* @param _value Amount of ETH to transfer
* @param _data Call data
- **/
+ */
function execute(
uint8[] calldata _sigV,
bytes32[] calldata _sigR,
@@ -111,7 +111,7 @@ contract MultiSig {
* @notice Allows to add a new owner
* @dev Transaction has to be sent by `execute` method.
* @param _owner Address of new owner
- **/
+ */
function addOwner(address _owner)
public
onlyThisContract
@@ -128,7 +128,7 @@ contract MultiSig {
* @notice Allows to remove an owner
* @dev Transaction has to be sent by `execute` method.
* @param _owner Address of owner
- **/
+ */
function removeOwner(address _owner)
public
onlyThisContract
@@ -149,7 +149,7 @@ contract MultiSig {
* @notice Allows to change the number of required signings
* @dev Transaction has to be sent by `execute` method
* @param _required Number of required signings
- **/
+ */
function changeRequirement(uint8 _required)
public
onlyThisContract
diff --git a/nucypher/blockchain/eth/sol/source/contracts/NuCypherToken.sol b/nucypher/blockchain/eth/sol/source/contracts/NuCypherToken.sol
index 612ad4737..9f25f1f77 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/NuCypherToken.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/NuCypherToken.sol
@@ -9,13 +9,13 @@ import "zeppelin/token/ERC20/ERC20Detailed.sol";
* @title NuCypher token
* @notice ERC20 token
* @dev Optional approveAndCall() functionality to notify a contract if an approve() has occurred.
-**/
+*/
contract NuCypherToken is ERC20, ERC20Detailed('NuCypher', 'NU', 18) {
/**
* @notice Set amount of tokens
* @param _totalSupply Total number of tokens
- **/
+ */
constructor (uint256 _totalSupply) public {
_mint(msg.sender, _totalSupply);
}
@@ -25,7 +25,7 @@ contract NuCypherToken is ERC20, ERC20Detailed('NuCypher', 'NU', 18) {
*
* @dev call the receiveApproval function on the contract you want to be notified.
* receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
- **/
+ */
function approveAndCall(address _spender, uint256 _value, bytes memory _extraData)
public returns (bool success)
{
@@ -39,7 +39,7 @@ contract NuCypherToken is ERC20, ERC20Detailed('NuCypher', 'NU', 18) {
/**
* @dev Interface to use the receiveApproval method
-**/
+*/
contract TokenRecipient {
/**
@@ -48,7 +48,7 @@ contract TokenRecipient {
* @param _value The amount of tokens to be spent
* @param _tokenContract Address of the token contract
* @param _extraData Extra data
- **/
+ */
function receiveApproval(address _from, uint256 _value, address _tokenContract, bytes calldata _extraData) external;
}
diff --git a/nucypher/blockchain/eth/sol/source/contracts/PolicyManager.sol b/nucypher/blockchain/eth/sol/source/contracts/PolicyManager.sol
index 84ffe8404..79d23cb14 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/PolicyManager.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/PolicyManager.sol
@@ -13,7 +13,8 @@ import "contracts/proxy/Upgradeable.sol";
/**
* @notice Contract holds policy data and locks fees
-**/
+* @dev |v1.1.2|
+*/
contract PolicyManager is Upgradeable {
using SafeERC20 for NuCypherToken;
using SafeMath for uint256;
@@ -92,7 +93,7 @@ contract PolicyManager is Upgradeable {
/**
* @notice Constructor sets address of the escrow contract
* @param _escrow Escrow contract
- **/
+ */
constructor(StakingEscrow _escrow) public {
// if the input address is not the StakingEscrow then calling `secondsPerPeriod` will throw error
secondsPerPeriod = _escrow.secondsPerPeriod();
@@ -102,7 +103,7 @@ contract PolicyManager is Upgradeable {
/**
* @dev Checks that sender is the StakingEscrow contract
- **/
+ */
modifier onlyEscrowContract()
{
require(msg.sender == address(escrow));
@@ -111,7 +112,7 @@ contract PolicyManager is Upgradeable {
/**
* @return Number of current period
- **/
+ */
function getCurrentPeriod() public view returns (uint16) {
return uint16(block.timestamp / secondsPerPeriod);
}
@@ -120,7 +121,7 @@ contract PolicyManager is Upgradeable {
* @notice Register a node
* @param _node Node address
* @param _period Initial period
- **/
+ */
function register(address _node, uint16 _period) external onlyEscrowContract {
NodeInfo storage nodeInfo = nodes[_node];
require(nodeInfo.lastMinedPeriod == 0);
@@ -129,7 +130,7 @@ contract PolicyManager is Upgradeable {
/**
* @notice Set the minimum reward that the node will take
- **/
+ */
function setMinRewardRate(uint256 _minRewardRate) public {
NodeInfo storage node = nodes[msg.sender];
node.minRewardRate = _minRewardRate;
@@ -143,7 +144,7 @@ contract PolicyManager is Upgradeable {
* @param _numberOfPeriods Duration of the policy in periods except first period
* @param _firstPartialReward Partial reward for first/current period
* @param _nodes Nodes that will handle policy
- **/
+ */
function createPolicy(
bytes16 _policyId,
uint16 _numberOfPeriods,
@@ -189,7 +190,7 @@ contract PolicyManager is Upgradeable {
* @notice Update node reward
* @param _node Node address
* @param _period Processed period
- **/
+ */
function updateReward(address _node, uint16 _period) external onlyEscrowContract {
NodeInfo storage node = nodes[_node];
if (node.lastMinedPeriod == 0 || _period <= node.lastMinedPeriod) {
@@ -204,7 +205,7 @@ contract PolicyManager is Upgradeable {
/**
* @notice Withdraw reward by node
- **/
+ */
function withdraw() public returns (uint256) {
return withdraw(msg.sender);
}
@@ -212,7 +213,7 @@ contract PolicyManager is Upgradeable {
/**
* @notice Withdraw reward by node
* @param _recipient Recipient of the reward
- **/
+ */
function withdraw(address payable _recipient) public returns (uint256) {
NodeInfo storage node = nodes[msg.sender];
uint256 reward = node.reward;
@@ -227,7 +228,7 @@ contract PolicyManager is Upgradeable {
* @notice Calculate amount of refund
* @param _policy Policy
* @param _arrangement Arrangement
- **/
+ */
function calculateRefundValue(Policy storage _policy, ArrangementInfo storage _arrangement)
internal view returns (uint256 refundValue, uint256 indexOfDowntimePeriods, uint16 lastRefundedPeriod)
{
@@ -288,7 +289,7 @@ contract PolicyManager is Upgradeable {
* @param _policyId Policy id
* @param _node Node that will be excluded or RESERVED_NODE if full policy should be used
( @param _forceRevoke Force revoke arrangement/policy
- **/
+ */
function refundInternal(bytes16 _policyId, address _node, bool _forceRevoke)
internal returns (uint256 refundValue)
{
@@ -348,7 +349,7 @@ contract PolicyManager is Upgradeable {
* @notice Calculate amount of refund
* @param _policyId Policy id
* @param _node Node or RESERVED_NODE if all nodes should be used
- **/
+ */
function calculateRefundValueInternal(bytes16 _policyId, address _node)
internal view returns (uint256 refundValue)
{
@@ -375,7 +376,7 @@ contract PolicyManager is Upgradeable {
/**
* @notice Revoke policy by client
* @param _policyId Policy id
- **/
+ */
function revokePolicy(bytes16 _policyId) public {
refundInternal(_policyId, RESERVED_NODE, true);
}
@@ -384,7 +385,7 @@ contract PolicyManager is Upgradeable {
* @notice Revoke arrangement by client
* @param _policyId Policy id
* @param _node Node that will be excluded
- **/
+ */
function revokeArrangement(bytes16 _policyId, address _node)
public returns (uint256 refundValue)
{
@@ -395,7 +396,7 @@ contract PolicyManager is Upgradeable {
/**
* @notice Refund part of fee by client
* @param _policyId Policy id
- **/
+ */
function refund(bytes16 _policyId) public {
refundInternal(_policyId, RESERVED_NODE, false);
}
@@ -404,7 +405,7 @@ contract PolicyManager is Upgradeable {
* @notice Refund part of one node's fee by client
* @param _policyId Policy id
* @param _node Node address
- **/
+ */
function refund(bytes16 _policyId, address _node)
public returns (uint256 refundValue)
{
@@ -415,7 +416,7 @@ contract PolicyManager is Upgradeable {
/**
* @notice Calculate amount of refund
* @param _policyId Policy id
- **/
+ */
function calculateRefundValue(bytes16 _policyId)
external view returns (uint256 refundValue)
{
@@ -426,7 +427,7 @@ contract PolicyManager is Upgradeable {
* @notice Calculate amount of refund
* @param _policyId Policy id
* @param _node Node
- **/
+ */
function calculateRefundValue(bytes16 _policyId, address _node)
external view returns (uint256 refundValue)
{
@@ -437,7 +438,7 @@ contract PolicyManager is Upgradeable {
/**
* @notice Get number of arrangements in the policy
* @param _policyId Policy id
- **/
+ */
function getArrangementsLength(bytes16 _policyId)
public view returns (uint256)
{
@@ -448,7 +449,7 @@ contract PolicyManager is Upgradeable {
* @notice Get information about node reward
* @param _node Address of node
* @param _period Period to get reward delta
- **/
+ */
function getNodeRewardDelta(address _node, uint16 _period)
public view returns (int256)
{
@@ -457,7 +458,7 @@ contract PolicyManager is Upgradeable {
/**
* @notice Return the information about arrangement
- **/
+ */
function getArrangementInfo(bytes16 _policyId, uint256 _index)
// TODO change to structure when ABIEncoderV2 is released (#1501)
// public view returns (ArrangementInfo)
@@ -472,7 +473,7 @@ contract PolicyManager is Upgradeable {
/**
* @dev Get Policy structure by delegatecall
- **/
+ */
function delegateGetPolicy(address _target, bytes16 _policyId)
internal returns (Policy memory result)
{
@@ -484,7 +485,7 @@ contract PolicyManager is Upgradeable {
/**
* @dev Get ArrangementInfo structure by delegatecall
- **/
+ */
function delegateGetArrangementInfo(address _target, bytes16 _policyId, uint256 _index)
internal returns (ArrangementInfo memory result)
{
@@ -497,7 +498,7 @@ contract PolicyManager is Upgradeable {
/**
* @dev Get NodeInfo structure by delegatecall
- **/
+ */
function delegateGetNodeInfo(address _target, address _node)
internal returns (NodeInfo memory result)
{
diff --git a/nucypher/blockchain/eth/sol/source/contracts/Seeder.sol b/nucypher/blockchain/eth/sol/source/contracts/Seeder.sol
index 68f1bbb76..a073e150c 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/Seeder.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/Seeder.sol
@@ -7,7 +7,7 @@ import "zeppelin/ownership/Ownable.sol";
/**
* @notice Contract holds references to seed
* node interface information for bootstrapping the network.
-**/
+*/
contract Seeder is Ownable {
struct SeedInfo {
@@ -21,14 +21,14 @@ contract Seeder is Ownable {
/**
* @param _maxSeeds The quantity of maximum seed nodes the contract can store
- **/
+ */
constructor(uint256 _maxSeeds) public {
seedArray = new address[](_maxSeeds);
}
/**
* @notice Returns the length of the seed nodes array
- **/
+ */
function getSeedArrayLength()
public view returns (uint256)
{
@@ -39,7 +39,7 @@ contract Seeder is Ownable {
* @notice Write a new seed address and interface info to contract storage
* @param _ip IPv4 address of the seed node
* @param _port TCP port of the seed node
- **/
+ */
function enroll(address _seed, string memory _ip, uint16 _port) public onlyOwner {
seeds[_seed] = SeedInfo(_ip, _port);
@@ -61,7 +61,7 @@ contract Seeder is Ownable {
* @notice Seed updates itself.
* @param _ip Updated IPv4 address of the existing seed node
* @param _port Updated TCP port of the existing seed node
- **/
+ */
function refresh(string memory _ip, uint16 _port) public {
SeedInfo storage seed = seeds[msg.sender];
require(seed.port != 0);
diff --git a/nucypher/blockchain/eth/sol/source/contracts/StakingEscrow.sol b/nucypher/blockchain/eth/sol/source/contracts/StakingEscrow.sol
index 82bc69970..2b51b9e72 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/StakingEscrow.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/StakingEscrow.sol
@@ -7,7 +7,7 @@ import "contracts/Issuer.sol";
/**
* @notice PolicyManager interface
-**/
+*/
contract PolicyManagerInterface {
function register(address _node, uint16 _period) external;
function updateReward(address _node, uint16 _period) external;
@@ -17,7 +17,7 @@ contract PolicyManagerInterface {
/**
* @notice Adjudicator interface
-**/
+*/
contract AdjudicatorInterface {
function escrow() public view returns (address);
}
@@ -25,7 +25,7 @@ contract AdjudicatorInterface {
/**
* @notice WorkLock interface
-**/
+*/
contract WorkLockInterface {
function escrow() public view returns (address);
}
@@ -34,7 +34,8 @@ contract WorkLockInterface {
/**
* @notice Contract holds and locks stakers tokens.
* Each staker that locks their tokens will receive some compensation
-**/
+* @dev |v1.4.1|
+*/
contract StakingEscrow is Issuer {
using SafeERC20 for NuCypherToken;
using AdditionalMath for uint256;
@@ -129,7 +130,7 @@ contract StakingEscrow is Issuer {
* @param _minAllowableLockedTokens Min amount of tokens that can be locked
* @param _maxAllowableLockedTokens Max amount of tokens that can be locked
* @param _minWorkerPeriods Min amount of periods while a worker can't be changed
- **/
+ */
constructor(
NuCypherToken _token,
uint32 _hoursPerPeriod,
@@ -160,7 +161,7 @@ contract StakingEscrow is Issuer {
/**
* @dev Checks the existence of a staker in the contract
- **/
+ */
modifier onlyStaker()
{
require(stakerInfo[msg.sender].value > 0);
@@ -170,7 +171,7 @@ contract StakingEscrow is Issuer {
//------------------------Initialization------------------------
/**
* @notice Set policy manager address
- **/
+ */
function setPolicyManager(PolicyManagerInterface _policyManager) external onlyOwner {
// Policy manager can be set only once
require(address(policyManager) == address(0));
@@ -181,7 +182,7 @@ contract StakingEscrow is Issuer {
/**
* @notice Set adjudicator address
- **/
+ */
function setAdjudicator(AdjudicatorInterface _adjudicator) external onlyOwner {
// Adjudicator can be set only once
require(address(adjudicator) == address(0));
@@ -192,7 +193,7 @@ contract StakingEscrow is Issuer {
/**
* @notice Set worklock address
- **/
+ */
function setWorkLock(WorkLockInterface _workLock) external onlyOwner {
// WorkLock can be set only once
require(address(workLock) == address(0));
@@ -204,7 +205,7 @@ contract StakingEscrow is Issuer {
//------------------------Main getters------------------------
/**
* @notice Get all tokens belonging to the staker
- **/
+ */
function getAllTokens(address _staker) external view returns (uint256) {
return stakerInfo[_staker].value;
}
@@ -213,7 +214,7 @@ contract StakingEscrow is Issuer {
* @notice Get the start period. Use in the calculation of the last period of the sub stake
* @param _info Staker structure
* @param _currentPeriod Current period
- **/
+ */
function getStartPeriod(StakerInfo storage _info, uint16 _currentPeriod)
internal view returns (uint16)
{
@@ -228,7 +229,7 @@ contract StakingEscrow is Issuer {
* @notice Get the last period of the sub stake
* @param _subStake Sub stake structure
* @param _startPeriod Pre-calculated start period
- **/
+ */
function getLastPeriodOfSubStake(SubStakeInfo storage _subStake, uint16 _startPeriod)
internal view returns (uint16)
{
@@ -246,7 +247,7 @@ contract StakingEscrow is Issuer {
* @notice Get the last period of the sub stake
* @param _staker Staker
* @param _index Stake index
- **/
+ */
function getLastPeriodOfSubStake(address _staker, uint256 _index)
external view returns (uint16)
{
@@ -263,7 +264,7 @@ contract StakingEscrow is Issuer {
* @param _info Staker structure
* @param _currentPeriod Current period
* @param _period Next period
- **/
+ */
function getLockedTokens(StakerInfo storage _info, uint16 _currentPeriod, uint16 _period)
internal view returns (uint256 lockedValue)
{
@@ -282,7 +283,7 @@ contract StakingEscrow is Issuer {
* @dev This function is used by PreallocationEscrow so its signature can't be updated.
* @param _staker Staker
* @param _periods Amount of periods that will be added to the current period
- **/
+ */
function getLockedTokens(address _staker, uint16 _periods)
external view returns (uint256 lockedValue)
{
@@ -297,7 +298,7 @@ contract StakingEscrow is Issuer {
* @dev Information may be incorrect for mined or unconfirmed surpassed period
* @param _staker Staker
* @param _periods Amount of periods that will be subtracted from the current period
- **/
+ */
function getLockedTokensInPast(address _staker, uint16 _periods)
external view returns (uint256 lockedValue)
{
@@ -310,7 +311,7 @@ contract StakingEscrow is Issuer {
/**
* @notice Get the last active staker's period
* @param _staker Staker
- **/
+ */
function getLastActivePeriod(address _staker) public view returns (uint16) {
StakerInfo storage info = stakerInfo[_staker];
if (info.confirmedPeriod1 != EMPTY_CONFIRMED_PERIOD ||
@@ -328,7 +329,7 @@ contract StakingEscrow is Issuer {
* @param _maxStakers Max stakers for looking, if set 0 then all will be used
* @return allLockedTokens Sum of locked tokens for active stakers
* @return activeStakers Array of stakers and their locked tokens. Stakers addresses stored as uint256
- **/
+ */
function getActiveStakers(uint16 _periods, uint256 _startIndex, uint256 _maxStakers)
external view returns (uint256 allLockedTokens, uint256[2][] memory activeStakers)
{
@@ -367,14 +368,14 @@ contract StakingEscrow is Issuer {
/**
* @notice Checks if `reStake` parameter is available for changing
* @param _staker Staker
- **/
+ */
function isReStakeLocked(address _staker) public view returns (bool) {
return getCurrentPeriod() < stakerInfo[_staker].lockReStakeUntilPeriod;
}
/**
* @notice Get worker using staker's address
- **/
+ */
function getWorkerFromStaker(address _staker) public view returns (address) {
StakerInfo storage info = stakerInfo[_staker];
// specified address is not a staker
@@ -386,14 +387,14 @@ contract StakingEscrow is Issuer {
/**
* @notice Get staker using worker's address
- **/
+ */
function getStakerFromWorker(address _worker) public view returns (address) {
return workerToStaker[_worker];
}
/**
* @notice Get work that completed by the staker
- **/
+ */
function getCompletedWork(address _staker) public view returns (uint256) {
return stakerInfo[_staker].completedWork;
}
@@ -403,7 +404,7 @@ contract StakingEscrow is Issuer {
* @dev If specified period is outside all downtime periods, the length of the array will be returned
* @param _staker Staker
* @param _period Specified period number
- **/
+ */
function findIndexOfPastDowntime(address _staker, uint16 _period) external view returns (uint256 index) {
StakerInfo storage info = stakerInfo[_staker];
for (index = 0; index < info.pastDowntime.length; index++) {
@@ -419,7 +420,7 @@ contract StakingEscrow is Issuer {
* @param _staker Staker
* @param _measureWork Value for `measureWork` parameter
* @return Work that was previously done
- **/
+ */
function setWorkMeasurement(address _staker, bool _measureWork) public returns (uint256) {
require(msg.sender == address(workLock));
StakerInfo storage info = stakerInfo[_staker];
@@ -430,7 +431,7 @@ contract StakingEscrow is Issuer {
/** @notice Set worker
* @param _worker Worker address. Must be a real address, not a contract
- **/
+ */
function setWorker(address _worker) public onlyStaker {
StakerInfo storage info = stakerInfo[msg.sender];
require(_worker != info.worker, "Specified worker is already set for this staker");
@@ -461,7 +462,7 @@ contract StakingEscrow is Issuer {
* @notice Set `reStake` parameter. If true then all staking rewards will be added to locked stake
* Only if this parameter is not locked
* @param _reStake Value for parameter
- **/
+ */
function setReStake(bool _reStake) public isInitialized {
require(!isReStakeLocked(msg.sender));
StakerInfo storage info = stakerInfo[msg.sender];
@@ -475,7 +476,7 @@ contract StakingEscrow is Issuer {
/**
* @notice Lock `reStake` parameter. Only if this parameter is not locked
* @param _lockReStakeUntilPeriod Can't change `reStake` value until this period
- **/
+ */
function lockReStake(uint16 _lockReStakeUntilPeriod) public isInitialized {
require(!isReStakeLocked(msg.sender) &&
_lockReStakeUntilPeriod > getCurrentPeriod());
@@ -490,7 +491,7 @@ contract StakingEscrow is Issuer {
* @param _value Amount of tokens to deposit
* @param _tokenContract Token contract address
* @notice (param _extraData) Amount of periods during which tokens will be locked
- **/
+ */
function receiveApproval(
address _from,
uint256 _value,
@@ -517,7 +518,7 @@ contract StakingEscrow is Issuer {
* @notice Deposit tokens
* @param _value Amount of tokens to deposit
* @param _periods Amount of periods during which tokens will be locked
- **/
+ */
function deposit(uint256 _value, uint16 _periods) external {
deposit(msg.sender, msg.sender, _value, _periods);
}
@@ -527,7 +528,7 @@ contract StakingEscrow is Issuer {
* @param _staker Staker
* @param _value Amount of tokens to deposit
* @param _periods Amount of periods during which tokens will be locked
- **/
+ */
function deposit(address _staker, uint256 _value, uint16 _periods) external {
deposit(_staker, msg.sender, _value, _periods);
}
@@ -538,7 +539,7 @@ contract StakingEscrow is Issuer {
* @param _payer Owner of tokens
* @param _value Amount of tokens to deposit
* @param _periods Amount of periods during which tokens will be locked
- **/
+ */
function deposit(address _staker, address _payer, uint256 _value, uint16 _periods) internal isInitialized {
require(_value != 0);
StakerInfo storage info = stakerInfo[_staker];
@@ -559,7 +560,7 @@ contract StakingEscrow is Issuer {
* @notice Lock some tokens as a stake
* @param _value Amount of tokens which will be locked
* @param _periods Amount of periods during which tokens will be locked
- **/
+ */
function lock(uint256 _value, uint16 _periods) external onlyStaker {
lock(msg.sender, _value, _periods);
}
@@ -569,7 +570,7 @@ contract StakingEscrow is Issuer {
* @param _staker Staker
* @param _value Amount of tokens which will be locked
* @param _periods Amount of periods during which tokens will be locked
- **/
+ */
function lock(address _staker, uint256 _value, uint16 _periods) internal {
require(_value >= minAllowableLockedTokens &&
_periods >= minLockedPeriods);
@@ -601,7 +602,7 @@ contract StakingEscrow is Issuer {
* @param _lastPeriod Last period of the sub stake
* @param _periods Duration of the sub stake in periods
* @param _lockedValue Amount of locked tokens
- **/
+ */
function saveSubStake(
StakerInfo storage _info,
uint16 _firstPeriod,
@@ -635,7 +636,7 @@ contract StakingEscrow is Issuer {
* @param _index Index of the sub stake
* @param _newValue New sub stake value
* @param _periods Amount of periods for extending sub stake
- **/
+ */
function divideStake(uint256 _index, uint256 _newValue, uint16 _periods) external onlyStaker {
StakerInfo storage info = stakerInfo[msg.sender];
require(_newValue >= minAllowableLockedTokens && _periods > 0);
@@ -658,7 +659,7 @@ contract StakingEscrow is Issuer {
* @notice Prolong active sub stake
* @param _index Index of the sub stake
* @param _periods Amount of periods for extending sub stake
- **/
+ */
function prolongStake(uint256 _index, uint16 _periods) external onlyStaker {
StakerInfo storage info = stakerInfo[msg.sender];
require(_periods > 0, "Incorrect parameters");
@@ -681,7 +682,7 @@ contract StakingEscrow is Issuer {
/**
* @notice Withdraw available amount of tokens to staker
* @param _value Amount of tokens to withdraw
- **/
+ */
function withdraw(uint256 _value) external onlyStaker {
uint16 currentPeriod = getCurrentPeriod();
uint16 nextPeriod = currentPeriod + 1;
@@ -698,7 +699,7 @@ contract StakingEscrow is Issuer {
/**
* @notice Confirm activity for the next period and mine for the previous period
- **/
+ */
function confirmActivity() external {
address staker = getStakerFromWorker(msg.sender);
StakerInfo storage info = stakerInfo[staker];
@@ -745,7 +746,7 @@ contract StakingEscrow is Issuer {
/**
* @notice Mint tokens for previous periods if staker locked their tokens and confirmed activity
- **/
+ */
function mint() external onlyStaker {
// save last active period to the storage if both periods will be empty after minting
// because we won't be able to calculate last active period
@@ -765,7 +766,7 @@ contract StakingEscrow is Issuer {
/**
* @notice Mint tokens for previous periods if staker locked their tokens and confirmed activity
* @param _staker Staker
- **/
+ */
function mint(address _staker) internal {
uint16 currentPeriod = getCurrentPeriod();
uint16 previousPeriod = currentPeriod - 1;
@@ -813,7 +814,7 @@ contract StakingEscrow is Issuer {
* @param _confirmedPeriodNumber Number of confirmed period (1 or 2)
* @param _currentPeriod Current period
* @param _startPeriod Pre-calculated start period
- **/
+ */
function mint(
address _staker,
StakerInfo storage _info,
@@ -864,7 +865,7 @@ contract StakingEscrow is Issuer {
* @param _penalty Penalty
* @param _investigator Investigator
* @param _reward Reward for the investigator
- **/
+ */
function slashStaker(
address _staker,
uint256 _penalty,
@@ -927,7 +928,7 @@ contract StakingEscrow is Issuer {
* @return nextLock Amount of tokens that locked in the next period and not locked in the current period
* @return currentAndNextLock Amount of tokens that locked in the current period and in the next period
* @return shortestSubStakeIndex Index of the shortest sub stake
- **/
+ */
function getLockedTokensAndShortestSubStake(
StakerInfo storage _info,
uint16 _currentPeriod,
@@ -980,7 +981,7 @@ contract StakingEscrow is Issuer {
* @param _decreasePeriod The period when the decrease begins
* @param _startPeriod Pre-calculated start period
* @param _shortestSubStakeIndex Index of the shortest period
- **/
+ */
function decreaseSubStakes(
StakerInfo storage _info,
uint256 _penalty,
@@ -1037,7 +1038,7 @@ contract StakingEscrow is Issuer {
* @return shortestSubStake The shortest sub stake
* @return minSubStakeDuration Duration of the shortest sub stake
* @return minSubStakeLastPeriod Last period of the shortest sub stake
- **/
+ */
function getShortestSubStake(
StakerInfo storage _info,
uint16 _currentPeriod,
@@ -1078,7 +1079,7 @@ contract StakingEscrow is Issuer {
* @param _firstPeriod First period of the old sub stake
* @param _lockedValue Locked value of the old sub stake
* @param _currentPeriod Current period, when the old sub stake is already unlocked
- **/
+ */
function saveOldSubStake(
StakerInfo storage _info,
uint16 _firstPeriod,
@@ -1117,21 +1118,21 @@ contract StakingEscrow is Issuer {
//-------------Additional getters for stakers info-------------
/**
* @notice Return the length of the array of stakers
- **/
+ */
function getStakersLength() external view returns (uint256) {
return stakers.length;
}
/**
* @notice Return the length of the array of sub stakes
- **/
+ */
function getSubStakesLength(address _staker) external view returns (uint256) {
return stakerInfo[_staker].subStakes.length;
}
/**
* @notice Return the information about sub stake
- **/
+ */
function getSubStakeInfo(address _staker, uint256 _index)
// TODO change to structure when ABIEncoderV2 is released (#1501)
// public view returns (SubStakeInfo)
@@ -1146,14 +1147,14 @@ contract StakingEscrow is Issuer {
/**
* @notice Return the length of the array of past downtime
- **/
+ */
function getPastDowntimeLength(address _staker) external view returns (uint256) {
return stakerInfo[_staker].pastDowntime.length;
}
/**
* @notice Return the information about past downtime
- **/
+ */
function getPastDowntime(address _staker, uint256 _index)
// TODO change to structure when ABIEncoderV2 is released (#1501)
// public view returns (Downtime)
@@ -1168,7 +1169,7 @@ contract StakingEscrow is Issuer {
//------------------------Upgradeable------------------------
/**
* @dev Get StakerInfo structure by delegatecall
- **/
+ */
function delegateGetStakerInfo(address _target, bytes32 _staker)
internal returns (StakerInfo memory result)
{
@@ -1185,7 +1186,7 @@ contract StakingEscrow is Issuer {
/**
* @dev Get SubStakeInfo structure by delegatecall
- **/
+ */
function delegateGetSubStakeInfo(address _target, bytes32 _staker, uint256 _index)
internal returns (SubStakeInfo memory result)
{
@@ -1198,7 +1199,7 @@ contract StakingEscrow is Issuer {
/**
* @dev Get Downtime structure by delegatecall
- **/
+ */
function delegateGetPastDowntime(address _target, bytes32 _staker, uint256 _index)
internal returns (Downtime memory result)
{
diff --git a/nucypher/blockchain/eth/sol/source/contracts/WorkLock.sol b/nucypher/blockchain/eth/sol/source/contracts/WorkLock.sol
index 55b79404a..43e290265 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/WorkLock.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/WorkLock.sol
@@ -9,7 +9,7 @@ import "contracts/StakingEscrow.sol";
/**
* @notice The WorkLock distribution contract
-**/
+*/
contract WorkLock {
using SafeMath for uint256;
using Address for address payable;
@@ -46,7 +46,7 @@ contract WorkLock {
* @param _depositRate ETH -> NU rate
* @param _refundRate Work -> ETH rate
* @param _lockedPeriods Number of periods during which claimed tokens will be locked
- **/
+ */
constructor(
NuCypherToken _token,
StakingEscrow _escrow,
@@ -78,7 +78,7 @@ contract WorkLock {
/**
* @notice Bid for tokens by transferring ETH
- **/
+ */
function bid() public payable returns (uint256 newClaimedTokens) {
require(block.timestamp >= startBidDate && block.timestamp <= endBidDate,
"Bid is open during a certain period");
@@ -96,7 +96,7 @@ contract WorkLock {
/**
* @notice Claimed tokens will be deposited and locked as stake in the StakingEscrow contract.
- **/
+ */
function claim() public returns (uint256 claimedTokens) {
require(block.timestamp >= endBidDate, "Claiming tokens allowed after bidding is over");
WorkInfo storage info = workInfo[msg.sender];
@@ -111,7 +111,7 @@ contract WorkLock {
/**
* @notice Refund ETH for the completed work
- **/
+ */
function refund() public returns (uint256 refundETH) {
WorkInfo storage info = workInfo[msg.sender];
require(info.claimed, "Tokens are not claimed");
@@ -135,7 +135,7 @@ contract WorkLock {
/**
* @notice Get remaining work to full refund
- **/
+ */
function getRemainingWork(address _staker) public view returns (uint256) {
WorkInfo storage info = workInfo[_staker];
uint256 completedWork = escrow.getCompletedWork(_staker).sub(info.completedWork);
diff --git a/nucypher/blockchain/eth/sol/source/contracts/lib/AdditionalMath.sol b/nucypher/blockchain/eth/sol/source/contracts/lib/AdditionalMath.sol
index 5eeb26520..3358ee440 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/lib/AdditionalMath.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/lib/AdditionalMath.sol
@@ -6,7 +6,7 @@ import "zeppelin/math/SafeMath.sol";
/**
* @notice Additional math operations
-**/
+*/
library AdditionalMath {
using SafeMath for uint256;
@@ -20,7 +20,7 @@ library AdditionalMath {
/**
* @notice Division and ceil
- **/
+ */
function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {
return (a.add(b) - 1) / b;
}
diff --git a/nucypher/blockchain/eth/sol/source/contracts/lib/ReEncryptionValidator.sol b/nucypher/blockchain/eth/sol/source/contracts/lib/ReEncryptionValidator.sol
index 660ee5144..530184a7c 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/lib/ReEncryptionValidator.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/lib/ReEncryptionValidator.sol
@@ -5,7 +5,7 @@ import "contracts/lib/SignatureVerifier.sol";
/**
* @notice Validates re-encryption correctness.
-**/
+*/
library ReEncryptionValidator {
using UmbralDeserializer for bytes;
@@ -43,7 +43,7 @@ library ReEncryptionValidator {
* @param _capsuleBytes Capsule
* @param _cFragBytes Capsule frag
* @param _precomputedBytes Additional precomputed data
- **/
+ */
function validateCFrag(
bytes memory _capsuleBytes,
bytes memory _cFragBytes,
diff --git a/nucypher/blockchain/eth/sol/source/contracts/lib/SignatureVerifier.sol b/nucypher/blockchain/eth/sol/source/contracts/lib/SignatureVerifier.sol
index 04d1766f0..5669cfd56 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/lib/SignatureVerifier.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/lib/SignatureVerifier.sol
@@ -4,7 +4,7 @@ pragma solidity ^0.5.3;
/**
* @notice Library to recover address and verify signatures
* @dev Simple wrapper for `ecrecover`
-**/
+*/
library SignatureVerifier {
enum HashAlgorithm {KECCAK256, SHA256, RIPEMD160}
@@ -16,7 +16,7 @@ library SignatureVerifier {
* @notice Recover signer address from hash and signature
* @param _hash 32 bytes message hash
* @param _signature Signature of hash - 32 bytes r + 32 bytes s + 1 byte v (could be 0, 1, 27, 28)
- **/
+ */
function recover(bytes32 _hash, bytes memory _signature)
internal
pure
@@ -44,7 +44,7 @@ library SignatureVerifier {
/**
* @notice Transform public key to address
* @param _publicKey secp256k1 public key
- **/
+ */
function toAddress(bytes memory _publicKey) internal pure returns (address) {
return address(uint160(uint256(keccak256(_publicKey))));
}
@@ -53,7 +53,7 @@ library SignatureVerifier {
* @notice Hash using one of pre built hashing algorithm
* @param _message Signed message
* @param _algorithm Hashing algorithm
- **/
+ */
function hash(bytes memory _message, HashAlgorithm _algorithm)
internal
pure
@@ -75,7 +75,7 @@ library SignatureVerifier {
* @param _signature Signature of message hash
* @param _publicKey secp256k1 public key in uncompressed format without prefix byte (64 bytes)
* @param _algorithm Hashing algorithm
- **/
+ */
function verify(
bytes memory _message,
bytes memory _signature,
@@ -96,7 +96,7 @@ library SignatureVerifier {
* @dev Only supports version 0 and version E (0x45)
* @param _message Message to sign
* @param _version EIP191 version to use
- **/
+ */
function hashEIP191(
bytes memory _message,
byte _version
@@ -140,7 +140,7 @@ library SignatureVerifier {
* @param _signature Signature of message hash
* @param _publicKey secp256k1 public key in uncompressed format without prefix byte (64 bytes)
* @param _version EIP191 version to use
- **/
+ */
function verifyEIP191(
bytes memory _message,
bytes memory _signature,
diff --git a/nucypher/blockchain/eth/sol/source/contracts/lib/UmbralDeserializer.sol b/nucypher/blockchain/eth/sol/source/contracts/lib/UmbralDeserializer.sol
index 9b29d3d50..57edf264f 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/lib/UmbralDeserializer.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/lib/UmbralDeserializer.sol
@@ -3,7 +3,7 @@ pragma solidity ^0.5.3;
/**
* @notice Deserialization library for Umbral objects
-**/
+*/
library UmbralDeserializer {
struct Point {
@@ -72,7 +72,7 @@ library UmbralDeserializer {
/**
* @notice Deserialize to capsule (not activated)
- **/
+ */
function toCapsule(bytes memory _capsuleBytes)
internal pure returns (Capsule memory capsule)
{
@@ -87,7 +87,7 @@ library UmbralDeserializer {
* @notice Deserialize to correctness proof
* @param _pointer Proof bytes memory pointer
* @param _proofBytesLength Proof bytes length
- **/
+ */
function toCorrectnessProof(uint256 _pointer, uint256 _proofBytesLength)
internal pure returns (CorrectnessProof memory proof)
{
@@ -111,7 +111,7 @@ library UmbralDeserializer {
/**
* @notice Deserialize to correctness proof
- **/
+ */
function toCorrectnessProof(bytes memory _proofBytes)
internal pure returns (CorrectnessProof memory proof)
{
@@ -121,7 +121,7 @@ library UmbralDeserializer {
/**
* @notice Deserialize to CapsuleFrag
- **/
+ */
function toCapsuleFrag(bytes memory _cFragBytes)
internal pure returns (CapsuleFrag memory cFrag)
{
@@ -140,7 +140,7 @@ library UmbralDeserializer {
/**
* @notice Deserialize to precomputed data
- **/
+ */
function toPreComputedData(bytes memory _preComputedData)
internal pure returns (PreComputedData memory data)
{
@@ -229,7 +229,7 @@ library UmbralDeserializer {
// TODO extract to external library if needed (#1500)
/**
* @notice Get the memory pointer for start of array
- **/
+ */
function getPointer(bytes memory _bytes) internal pure returns (uint256 pointer) {
assembly {
pointer := add(_bytes, 32) // skip array length
@@ -238,7 +238,7 @@ library UmbralDeserializer {
/**
* @notice Copy point data from memory in the pointer position
- **/
+ */
function copyPoint(uint256 _pointer, Point memory _point)
internal pure returns (uint256 resultPointer)
{
@@ -256,7 +256,7 @@ library UmbralDeserializer {
/**
* @notice Read 1 byte from memory in the pointer position
- **/
+ */
function getByte(uint256 _pointer) internal pure returns (byte result) {
bytes32 word;
assembly {
@@ -268,7 +268,7 @@ library UmbralDeserializer {
/**
* @notice Read 32 bytes from memory in the pointer position
- **/
+ */
function getBytes32(uint256 _pointer) internal pure returns (bytes32 result) {
assembly {
result := mload(_pointer)
@@ -282,7 +282,7 @@ library UmbralDeserializer {
* @param _bytesPointer Source memory pointer
* @param _target Target array
* @param _bytesLength Number of bytes to copy
- **/
+ */
function copyBytes(uint256 _bytesPointer, bytes memory _target, uint256 _bytesLength)
internal
pure
diff --git a/nucypher/blockchain/eth/sol/source/contracts/proxy/Dispatcher.sol b/nucypher/blockchain/eth/sol/source/contracts/proxy/Dispatcher.sol
index 502f6c20b..ff383753c 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/proxy/Dispatcher.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/proxy/Dispatcher.sol
@@ -8,7 +8,7 @@ import "zeppelin/utils/Address.sol";
/**
* @notice Proxying requests to other contracts.
* Client should use ABI of real contract and address of this contract
-**/
+*/
contract Dispatcher is Upgradeable {
using Address for address;
@@ -17,7 +17,7 @@ contract Dispatcher is Upgradeable {
/**
* @dev Set upgrading status before and after operations
- **/
+ */
modifier upgrading()
{
isUpgrade = UPGRADE_TRUE;
@@ -28,7 +28,7 @@ contract Dispatcher is Upgradeable {
/**
* @param _target Target contract address
* @param _newSecretHash Secret hash (keccak256)
- **/
+ */
constructor(address _target, bytes32 _newSecretHash) public upgrading {
require(_target.isContract());
// Checks that target contract inherits Dispatcher state
@@ -46,7 +46,7 @@ contract Dispatcher is Upgradeable {
* @param _target New target contract address
* @param _secret Secret for proof of contract owning
* @param _newSecretHash New secret hash (keccak256)
- **/
+ */
function upgrade(address _target, bytes memory _secret, bytes32 _newSecretHash) public onlyOwner upgrading {
require(_target.isContract());
require(keccak256(_secret) == secretHash && _newSecretHash != secretHash);
@@ -69,7 +69,7 @@ contract Dispatcher is Upgradeable {
* @dev Test storage carefully before upgrade again after rollback
* @param _secret Secret for proof of contract owning
* @param _newSecretHash New secret hash (keccak256)
- **/
+ */
function rollback(bytes memory _secret, bytes32 _newSecretHash) public onlyOwner upgrading {
require(previousTarget.isContract());
require(keccak256(_secret) == secretHash && _newSecretHash != secretHash);
@@ -88,7 +88,7 @@ contract Dispatcher is Upgradeable {
/**
* @dev Call verifyState method for Upgradeable contract
- **/
+ */
function verifyUpgradeableState(address _from, address _to) private {
(bool callSuccess,) = _from.delegatecall(abi.encodeWithSignature("verifyState(address)", _to));
require(callSuccess);
@@ -96,7 +96,7 @@ contract Dispatcher is Upgradeable {
/**
* @dev Call finishUpgrade method from the Upgradeable contract
- **/
+ */
function finishUpgrade() private {
(bool callSuccess,) = target.delegatecall(abi.encodeWithSignature("finishUpgrade(address)", target));
require(callSuccess);
@@ -113,12 +113,12 @@ contract Dispatcher is Upgradeable {
/**
* @dev Override function using empty code because no reason to call this function in Dispatcher
- **/
+ */
function finishUpgrade(address) public {}
/**
* @dev Fallback function send all requests to the target contract
- **/
+ */
function () external payable {
assert(target.isContract());
// execute requested function from target contract using storage of the dispatcher
diff --git a/nucypher/blockchain/eth/sol/source/contracts/proxy/Upgradeable.sol b/nucypher/blockchain/eth/sol/source/contracts/proxy/Upgradeable.sol
index 4500bbf42..00236b848 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/proxy/Upgradeable.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/proxy/Upgradeable.sol
@@ -9,7 +9,7 @@ import "zeppelin/ownership/Ownable.sol";
* @dev Inherited contract should implement verifyState(address) method by checking storage variables
* (see verifyState(address) in Dispatcher). Also contract should implement finishUpgrade(address)
* if it is using constructor parameters by coping this parameters to the dispatcher storage
-**/
+*/
contract Upgradeable is Ownable {
event StateVerified(address indexed testTarget, address sender);
@@ -19,22 +19,22 @@ contract Upgradeable is Ownable {
* @dev Contracts at the target must reserve the same location in storage for this address as in Dispatcher
* Stored data actually lives in the Dispatcher
* However the storage layout is specified here in the implementing contracts
- **/
+ */
address public target;
/**
* @dev Previous contract address (if available). Used for rollback
- **/
+ */
address public previousTarget;
/**
* @dev Secret hash to proof that user owns previous version of a contract
- **/
+ */
bytes32 public secretHash;
/**
* @dev Upgrade status. Explicit `uint8` type is used instead of `bool` to save gas by excluding 0 value
- **/
+ */
uint8 public isUpgrade;
/** Constants for `isUpgrade` field **/
@@ -44,7 +44,7 @@ contract Upgradeable is Ownable {
/**
* @dev Checks that function executed while upgrading
* Recommended to add to `verifyState` and `finishUpgrade` methods
- **/
+ */
modifier onlyWhileUpgrading()
{
require(isUpgrade == UPGRADE_TRUE);
@@ -54,7 +54,7 @@ contract Upgradeable is Ownable {
/**
* @dev Method for verifying storage state.
* Should check that new target contract returns right storage value
- **/
+ */
function verifyState(address _testTarget) public onlyWhileUpgrading {
emit StateVerified(_testTarget, msg.sender);
}
@@ -62,7 +62,7 @@ contract Upgradeable is Ownable {
/**
* @dev Copy values from the new target to the current storage
* @param _target New target contract address
- **/
+ */
function finishUpgrade(address _target) public onlyWhileUpgrading {
emit UpgradeFinished(_target, msg.sender);
}
@@ -75,7 +75,7 @@ contract Upgradeable is Ownable {
* @param _argument1 First method argument
* @param _argument2 Second method argument
* @return Address in memory where the data is located
- **/
+ */
function delegateGetData(
address _target,
string memory _signature,
@@ -108,7 +108,7 @@ contract Upgradeable is Ownable {
/**
* @dev Call "getter" without parameters.
* Result should not exceed 32 bytes
- **/
+ */
function delegateGet(address _target, string memory _signature)
internal returns (uint256 result)
{
@@ -121,7 +121,7 @@ contract Upgradeable is Ownable {
/**
* @dev Call "getter" with one parameter.
* Result should not exceed 32 bytes
- **/
+ */
function delegateGet(address _target, string memory _signature, bytes32 _argument)
internal returns (uint256 result)
{
@@ -134,7 +134,7 @@ contract Upgradeable is Ownable {
/**
* @dev Call "getter" with two parameters.
* Result should not exceed 32 bytes
- **/
+ */
function delegateGet(
address _target,
string memory _signature,
diff --git a/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/AbstractStakingContract.sol b/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/AbstractStakingContract.sol
index ea496c157..08b85f398 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/AbstractStakingContract.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/AbstractStakingContract.sol
@@ -7,7 +7,7 @@ import "zeppelin/utils/Address.sol";
/**
* @notice Router for accessing interface contract
-**/
+*/
contract StakingInterfaceRouter is Ownable {
using Address for address;
@@ -17,7 +17,7 @@ contract StakingInterfaceRouter is Ownable {
/**
* @param _target Address of the interface contract
* @param _newSecretHash Secret hash (keccak256)
- **/
+ */
constructor(address _target, bytes32 _newSecretHash) public {
require(_target.isContract());
target = _target;
@@ -29,7 +29,7 @@ contract StakingInterfaceRouter is Ownable {
* @param _target New contract address
* @param _secret Secret for proof of contract owning
* @param _newSecretHash New secret hash (keccak256)
- **/
+ */
function upgrade(address _target, bytes memory _secret, bytes32 _newSecretHash) public onlyOwner {
require(_target.isContract());
require(keccak256(_secret) == secretHash && _newSecretHash != secretHash);
@@ -43,7 +43,7 @@ contract StakingInterfaceRouter is Ownable {
/**
* @notice Base class for any staking contract
* @dev Implement `isFallbackAllowed()` or override fallback function
-**/
+*/
contract AbstractStakingContract {
using Address for address;
@@ -51,7 +51,7 @@ contract AbstractStakingContract {
/**
* @param _router Interface router contract address
- **/
+ */
constructor(StakingInterfaceRouter _router) public {
// check that the input address is contract
require(_router.target().isContract());
@@ -60,12 +60,12 @@ contract AbstractStakingContract {
/**
* @dev Checks permission for calling fallback function
- **/
+ */
function isFallbackAllowed() public returns (bool);
/**
* @dev Function sends all requests to the target contract
- **/
+ */
function () external payable {
require(isFallbackAllowed());
address target = router.target();
diff --git a/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/PreallocationEscrow.sol b/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/PreallocationEscrow.sol
index db720d9df..0ef2b991d 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/PreallocationEscrow.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/PreallocationEscrow.sol
@@ -10,7 +10,7 @@ import "contracts/staking_contracts/AbstractStakingContract.sol";
/**
* @notice StakingEscrow interface
-**/
+*/
contract StakingEscrowInterface {
function getAllTokens(address _staker) public view returns (uint256);
function secondsPerPeriod() public view returns (uint32);
@@ -19,7 +19,7 @@ contract StakingEscrowInterface {
/**
* @notice Contract holds tokens for vesting.
* Also tokens can be used as a stake in the staking escrow contract
-**/
+*/
contract PreallocationEscrow is AbstractStakingContract, Ownable {
using SafeERC20 for NuCypherToken;
using SafeMath for uint256;
@@ -38,7 +38,7 @@ contract PreallocationEscrow is AbstractStakingContract, Ownable {
* @param _router Address of the StakingInterfaceRouter contract
* @param _token Address of the NuCypher token contract
* @param _stakingEscrow Address of the StakingEscrow contract
- **/
+ */
constructor(
StakingInterfaceRouter _router,
NuCypherToken _token,
@@ -56,7 +56,7 @@ contract PreallocationEscrow is AbstractStakingContract, Ownable {
* @notice Initial tokens deposit
* @param _value Amount of token to deposit
* @param _duration Duration of tokens locking
- **/
+ */
function initialDeposit(uint256 _value, uint256 _duration) public {
require(lockedValue == 0 && _value > 0);
endLockTimestamp = block.timestamp.add(_duration);
@@ -67,7 +67,7 @@ contract PreallocationEscrow is AbstractStakingContract, Ownable {
/**
* @notice Get locked tokens value
- **/
+ */
function getLockedTokens() public view returns (uint256) {
if (endLockTimestamp <= block.timestamp) {
return 0;
@@ -78,7 +78,7 @@ contract PreallocationEscrow is AbstractStakingContract, Ownable {
/**
* @notice Withdraw available amount of tokens to owner
* @param _value Amount of token to withdraw
- **/
+ */
function withdrawTokens(uint256 _value) public onlyOwner {
uint256 balance = token.balanceOf(address(this));
require(balance >= _value);
@@ -91,7 +91,7 @@ contract PreallocationEscrow is AbstractStakingContract, Ownable {
/**
* @notice Withdraw available ETH to the owner
- **/
+ */
function withdrawETH() public onlyOwner {
uint256 balance = address(this).balance;
require(balance != 0);
@@ -101,7 +101,7 @@ contract PreallocationEscrow is AbstractStakingContract, Ownable {
/**
* @notice Calling fallback function is allowed only for the owner
- **/
+ */
function isFallbackAllowed() public returns (bool) {
return msg.sender == owner();
}
diff --git a/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/StakingInterface.sol b/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/StakingInterface.sol
index 5cec76ea8..993bbac3c 100644
--- a/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/StakingInterface.sol
+++ b/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/StakingInterface.sol
@@ -9,9 +9,10 @@ import "contracts/PolicyManager.sol";
/**
* @notice Interface for accessing main contracts from a staking contract
-* @dev All methods must be stateless because this code will execute by delegatecall call
-* If state is needed - use getStateContract() method to access state of this contract
-**/
+* @dev All methods must be stateless because this code will be executed by delegatecall call.
+* If state is needed - use getStateContract() method to access state of this contract.
+* @dev |v1.2.1|
+*/
contract StakingInterface {
event DepositedAsStaker(address indexed sender, uint256 value, uint16 periods);
@@ -35,7 +36,7 @@ contract StakingInterface {
* @param _token Token contract
* @param _escrow Escrow contract
* @param _policyManager PolicyManager contract
- **/
+ */
constructor(
NuCypherToken _token,
StakingEscrow _escrow,
@@ -54,7 +55,7 @@ contract StakingInterface {
/**
* @notice Get contract which stores state
* @dev Assume that `this` is the staking contract
- **/
+ */
function getStateContract() internal view returns (StakingInterface) {
address payable stakingContractAddress = address(bytes20(address(this)));
StakingInterfaceRouter router = AbstractStakingContract(stakingContractAddress).router();
@@ -64,7 +65,7 @@ contract StakingInterface {
/**
* @notice Set `worker` parameter in the staking escrow
* @param _worker Worker address
- **/
+ */
function setWorker(address _worker) public {
getStateContract().escrow().setWorker(_worker);
emit WorkerSet(msg.sender, _worker);
@@ -73,7 +74,7 @@ contract StakingInterface {
/**
* @notice Set `reStake` parameter in the staking escrow
* @param _reStake Value for parameter
- **/
+ */
function setReStake(bool _reStake) public {
getStateContract().escrow().setReStake(_reStake);
emit ReStakeSet(msg.sender, _reStake);
@@ -82,7 +83,7 @@ contract StakingInterface {
/**
* @notice Lock `reStake` parameter in the staking escrow
* @param _lockReStakeUntilPeriod Can't change `reStake` value until this period
- **/
+ */
function lockReStake(uint16 _lockReStakeUntilPeriod) public {
getStateContract().escrow().lockReStake(_lockReStakeUntilPeriod);
emit ReStakeLocked(msg.sender, _lockReStakeUntilPeriod);
@@ -92,7 +93,7 @@ contract StakingInterface {
* @notice Deposit tokens to the staking escrow
* @param _value Amount of token to deposit
* @param _periods Amount of periods during which tokens will be locked
- **/
+ */
function depositAsStaker(uint256 _value, uint16 _periods) public {
StakingInterface state = getStateContract();
NuCypherToken tokenFromState = state.token();
@@ -106,7 +107,7 @@ contract StakingInterface {
/**
* @notice Withdraw available amount of tokens from the staking escrow to the staking contract
* @param _value Amount of token to withdraw
- **/
+ */
function withdrawAsStaker(uint256 _value) public {
getStateContract().escrow().withdraw(_value);
emit WithdrawnAsStaker(msg.sender, _value);
@@ -116,7 +117,7 @@ contract StakingInterface {
* @notice Lock some tokens or increase lock in the staking escrow
* @param _value Amount of tokens which should lock
* @param _periods Amount of periods during which tokens will be locked
- **/
+ */
function lock(uint256 _value, uint16 _periods) public {
getStateContract().escrow().lock(_value, _periods);
emit Locked(msg.sender, _value, _periods);
@@ -127,7 +128,7 @@ contract StakingInterface {
* @param _index Index of stake
* @param _newValue New stake value
* @param _periods Amount of periods for extending stake
- **/
+ */
function divideStake(
uint256 _index,
uint256 _newValue,
@@ -141,7 +142,7 @@ contract StakingInterface {
/**
* @notice Mint tokens in the staking escrow
- **/
+ */
function mint() external {
getStateContract().escrow().mint();
emit Mined(msg.sender);
@@ -149,7 +150,7 @@ contract StakingInterface {
/**
* @notice Withdraw available reward from the policy manager to the staking contract
- **/
+ */
function withdrawPolicyReward(address payable _recipient) public {
uint256 value = getStateContract().policyManager().withdraw(_recipient);
emit PolicyRewardWithdrawn(_recipient, value);
@@ -157,7 +158,7 @@ contract StakingInterface {
/**
* @notice Set the minimum reward that the staker will take in the policy manager
- **/
+ */
function setMinRewardRate(uint256 _minRewardRate) public {
getStateContract().policyManager().setMinRewardRate(_minRewardRate);
emit MinRewardRateSet(msg.sender, _minRewardRate);
@@ -168,7 +169,7 @@ contract StakingInterface {
* @notice Prolong active sub stake
* @param _index Index of the sub stake
* @param _periods Amount of periods for extending sub stake
- **/
+ */
function prolongStake(uint256 _index, uint16 _periods) public {
getStateContract().escrow().prolongStake(_index, _periods);
emit Prolonged(msg.sender, _index, _periods);
diff --git a/nucypher/cli/deploy.py b/nucypher/cli/deploy.py
index c03040ba1..38ef6ea91 100644
--- a/nucypher/cli/deploy.py
+++ b/nucypher/cli/deploy.py
@@ -135,12 +135,13 @@ def inspect(provider_uri, config_root, registry_infile, deployer_address, poa):
@_admin_actor_options
@click.option('--retarget', '-d', help="Retarget a contract's proxy.", is_flag=True)
@click.option('--target-address', help="Address of the target contract", type=EIP55_CHECKSUM_ADDRESS)
+@click.option('--ignore-deployed', help="Ignore already deployed contracts if exist.", is_flag=True)
def upgrade(# Admin Actor Options
provider_uri, contract_name, config_root, poa, force, etherscan, hw_wallet, deployer_address,
registry_infile, registry_outfile, dev,
# Other
- retarget, target_address):
+ retarget, target_address, ignore_deployed):
"""
Upgrade NuCypher existing proxy contract deployments.
"""
@@ -188,7 +189,8 @@ def upgrade(# Admin Actor Options
click.confirm(f"Confirm deploy new version of {contract_name} and retarget proxy?", abort=True)
receipts = ADMINISTRATOR.upgrade_contract(contract_name=contract_name,
existing_plaintext_secret=existing_secret,
- new_plaintext_secret=new_secret)
+ new_plaintext_secret=new_secret,
+ ignore_deployed=ignore_deployed)
emitter.message(f"Successfully deployed and upgraded {contract_name}", color='green')
for name, receipt in receipts.items():
paint_receipt_summary(emitter=emitter, receipt=receipt)
@@ -237,12 +239,13 @@ def rollback(# Admin Actor Options
@_admin_actor_options
@click.option('--bare', help="Deploy a contract *only* without any additional operations.", is_flag=True)
@click.option('--gas', help="Operate with a specified gas per-transaction limit", type=click.IntRange(min=1))
+@click.option('--ignore-deployed', help="Ignore already deployed contracts if exist.", is_flag=True)
def contracts(# Admin Actor Options
provider_uri, contract_name, config_root, poa, force, etherscan, hw_wallet, deployer_address,
registry_infile, registry_outfile, dev,
# Other
- bare, gas):
+ bare, gas, ignore_deployed):
"""
Compile and deploy contracts.
"""
@@ -288,12 +291,14 @@ def contracts(# Admin Actor Options
receipts, agent = ADMINISTRATOR.deploy_contract(contract_name=contract_name,
plaintext_secret=secret,
gas_limit=gas,
- bare=bare)
+ bare=bare,
+ ignore_deployed=ignore_deployed)
else:
# Non-Upgradeable or Bare
receipts, agent = ADMINISTRATOR.deploy_contract(contract_name=contract_name,
gas_limit=gas,
- bare=bare)
+ bare=bare,
+ ignore_deployed=ignore_deployed)
# Report
paint_contract_deployment(contract_name=contract_name,
@@ -330,7 +335,8 @@ def contracts(# Admin Actor Options
deployment_receipts = ADMINISTRATOR.deploy_network_contracts(secrets=secrets,
emitter=emitter,
interactive=not force,
- etherscan=etherscan)
+ etherscan=etherscan,
+ ignore_deployed=ignore_deployed)
# Paint outfile paths
registry_outfile = local_registry.filepath
diff --git a/nucypher/cli/painting.py b/nucypher/cli/painting.py
index e6b75ddeb..f1721644f 100644
--- a/nucypher/cli/painting.py
+++ b/nucypher/cli/painting.py
@@ -260,7 +260,7 @@ Registry ................ {registry.filepath}
from nucypher.blockchain.eth.actors import ContractAdministrator
for contract_deployer_class in ContractAdministrator.dispatched_upgradeable_deployer_classes:
try:
- bare_contract = blockchain.get_contract_by_name(name=contract_deployer_class.contract_name,
+ bare_contract = blockchain.get_contract_by_name(contract_name=contract_deployer_class.contract_name,
proxy_name=DispatcherDeployer.contract_name,
registry=registry,
use_proxy_address=False)
@@ -297,7 +297,7 @@ Registry ................ {registry.filepath}
#
staking_interface_agent = PreallocationEscrowAgent.StakingInterfaceAgent(registry=registry)
- bare_contract = blockchain.get_contract_by_name(name=staking_interface_agent.contract_name,
+ bare_contract = blockchain.get_contract_by_name(contract_name=staking_interface_agent.contract_name,
proxy_name=StakingInterfaceRouterDeployer.contract_name,
use_proxy_address=False,
registry=registry)
diff --git a/nucypher/utilities/sandbox/blockchain.py b/nucypher/utilities/sandbox/blockchain.py
index c1d72f9de..efb012827 100644
--- a/nucypher/utilities/sandbox/blockchain.py
+++ b/nucypher/utilities/sandbox/blockchain.py
@@ -69,7 +69,7 @@ class TesterBlockchain(BlockchainDeployerInterface):
_PROVIDER_URI = 'tester://pyevm'
TEST_CONTRACTS_DIR = os.path.join(BASE_DIR, 'tests', 'blockchain', 'eth', 'contracts', 'contracts')
- _compiler = SolidityCompiler(test_contract_dir=TEST_CONTRACTS_DIR)
+ _compiler = SolidityCompiler(source_dirs=[(SolidityCompiler.default_contract_dir(), {TEST_CONTRACTS_DIR})])
_test_account_cache = list()
_default_test_accounts = NUMBER_OF_ETH_TEST_ACCOUNTS
diff --git a/tests/blockchain/eth/contracts/contracts/AdjudicatorTestSet.sol b/tests/blockchain/eth/contracts/contracts/AdjudicatorTestSet.sol
index 47b228345..70168e249 100644
--- a/tests/blockchain/eth/contracts/contracts/AdjudicatorTestSet.sol
+++ b/tests/blockchain/eth/contracts/contracts/AdjudicatorTestSet.sol
@@ -9,7 +9,7 @@ import "contracts/proxy/Upgradeable.sol";
/**
* @notice Contract for testing the Adjudicator contract
-**/
+*/
contract StakingEscrowForAdjudicatorMock {
uint32 public secondsPerPeriod = 1;
@@ -50,7 +50,7 @@ contract StakingEscrowForAdjudicatorMock {
/**
* @notice Upgrade to this contract must lead to fail
-**/
+*/
contract AdjudicatorBad is Upgradeable {
StakingEscrow public escrow;
@@ -67,7 +67,7 @@ contract AdjudicatorBad is Upgradeable {
/**
* @notice Contract for testing upgrading the Adjudicator contract
-**/
+*/
contract AdjudicatorV2Mock is Adjudicator {
uint256 public valueToCheck;
diff --git a/tests/blockchain/eth/contracts/contracts/IssuerTestSet.sol b/tests/blockchain/eth/contracts/contracts/IssuerTestSet.sol
index 5c0fada12..db520ef76 100644
--- a/tests/blockchain/eth/contracts/contracts/IssuerTestSet.sol
+++ b/tests/blockchain/eth/contracts/contracts/IssuerTestSet.sol
@@ -8,7 +8,7 @@ import "contracts/proxy/Upgradeable.sol";
/**
* @dev Contract for testing internal methods in the Issuer contract
-**/
+*/
contract IssuerMock is Issuer {
constructor(
@@ -54,7 +54,7 @@ contract IssuerMock is Issuer {
/**
* @notice Upgrade to this contract must lead to fail
-**/
+*/
contract IssuerBad is Upgradeable {
address public token;
@@ -72,7 +72,7 @@ contract IssuerBad is Upgradeable {
/**
* @notice Contract for testing upgrading the Issuer contract
-**/
+*/
contract IssuerV2Mock is Issuer {
uint256 public valueToCheck;
diff --git a/tests/blockchain/eth/contracts/contracts/LibTestSet.sol b/tests/blockchain/eth/contracts/contracts/LibTestSet.sol
index e93bc1182..da622b215 100644
--- a/tests/blockchain/eth/contracts/contracts/LibTestSet.sol
+++ b/tests/blockchain/eth/contracts/contracts/LibTestSet.sol
@@ -7,7 +7,7 @@ import "contracts/lib/ReEncryptionValidator.sol";
/**
* @notice Contract for using SignatureVerifier library
-**/
+*/
contract SignatureVerifierMock {
function recover(bytes32 _hash, bytes memory _signature)
@@ -72,7 +72,7 @@ contract SignatureVerifierMock {
/**
* @dev Contract for testing UmbralDeserializer library
-**/
+*/
contract UmbralDeserializerMock {
using UmbralDeserializer for bytes;
@@ -178,7 +178,7 @@ contract UmbralDeserializerMock {
/**
* @notice Contract for using ReEncryptionValidator library
-**/
+*/
contract ReEncryptionValidatorMock {
using UmbralDeserializer for bytes;
diff --git a/tests/blockchain/eth/contracts/contracts/PolicyManagerTestSet.sol b/tests/blockchain/eth/contracts/contracts/PolicyManagerTestSet.sol
index 647e2ec0e..d71dcabd2 100644
--- a/tests/blockchain/eth/contracts/contracts/PolicyManagerTestSet.sol
+++ b/tests/blockchain/eth/contracts/contracts/PolicyManagerTestSet.sol
@@ -7,7 +7,7 @@ import "contracts/StakingEscrow.sol";
/**
* @notice Upgrade to this contract must lead to fail
-**/
+*/
contract PolicyManagerBad is PolicyManager {
constructor(StakingEscrow _escrow) public PolicyManager(_escrow) {
@@ -22,7 +22,7 @@ contract PolicyManagerBad is PolicyManager {
/**
* @notice Contract for testing upgrading the PolicyManager contract
-**/
+*/
contract PolicyManagerV2Mock is PolicyManager {
uint256 public valueToCheck;
@@ -43,7 +43,7 @@ contract PolicyManagerV2Mock is PolicyManager {
/**
* @notice Contract for using in PolicyManager tests
-**/
+*/
contract StakingEscrowForPolicyMock {
struct Downtime {
@@ -58,28 +58,28 @@ contract StakingEscrowForPolicyMock {
/**
* @param _hoursPerPeriod Size of period in hours
- **/
+ */
constructor(uint16 _hoursPerPeriod) public {
secondsPerPeriod = uint32(_hoursPerPeriod * 1 hours);
}
/**
* @return Number of current period
- **/
+ */
function getCurrentPeriod() public view returns (uint16) {
return uint16(block.timestamp / secondsPerPeriod);
}
/**
* @notice Set last active period
- **/
+ */
function setLastActivePeriod(uint16 _lastActivePeriod) external {
lastActivePeriod = _lastActivePeriod;
}
/**
* @notice Add downtime period
- **/
+ */
function pushDowntimePeriod(uint16 _startPeriod, uint16 _endPeriod) external {
downtime.push(Downtime(_startPeriod, _endPeriod));
}
@@ -89,7 +89,7 @@ contract StakingEscrowForPolicyMock {
* @param _staker Staker on behalf of whom minting will be
* @param _startPeriod Start period for minting
* @param _numberOfPeriods Number periods for minting
- **/
+ */
function mint(address _staker, uint16 _startPeriod, uint16 _numberOfPeriods) public {
for (uint16 i = 0; i < _numberOfPeriods; i++) {
policyManager.updateReward(_staker, i + _startPeriod);
@@ -100,14 +100,14 @@ contract StakingEscrowForPolicyMock {
* @notice Emulate mint method
* @param _startPeriod Start period for minting
* @param _numberOfPeriods Number periods for minting
- **/
+ */
function mint(uint16 _startPeriod, uint16 _numberOfPeriods) external {
mint(msg.sender, _startPeriod, _numberOfPeriods);
}
/**
* @notice Set policy manager address
- **/
+ */
function setPolicyManager(PolicyManager _policyManager) external {
policyManager = _policyManager;
}
diff --git a/tests/blockchain/eth/contracts/contracts/ReceiveApprovalMethodMock.sol b/tests/blockchain/eth/contracts/contracts/ReceiveApprovalMethodMock.sol
index faad9bf62..e46fae3b0 100644
--- a/tests/blockchain/eth/contracts/contracts/ReceiveApprovalMethodMock.sol
+++ b/tests/blockchain/eth/contracts/contracts/ReceiveApprovalMethodMock.sol
@@ -3,7 +3,7 @@ pragma solidity ^0.5.3;
/**
* @notice Contract for using in token tests
-**/
+*/
contract ReceiveApprovalMethodMock {
address public sender;
diff --git a/tests/blockchain/eth/contracts/contracts/StakingContractsTestSet.sol b/tests/blockchain/eth/contracts/contracts/StakingContractsTestSet.sol
index 560bc1ef0..f41219eda 100644
--- a/tests/blockchain/eth/contracts/contracts/StakingContractsTestSet.sol
+++ b/tests/blockchain/eth/contracts/contracts/StakingContractsTestSet.sol
@@ -6,7 +6,7 @@ import "contracts/NuCypherToken.sol";
/**
* @notice Contract for using in staking contracts tests
-**/
+*/
contract StakingEscrowForStakingContractMock {
NuCypherToken token;
@@ -83,7 +83,7 @@ contract StakingEscrowForStakingContractMock {
/**
* @notice Contract for staking contract tests
-**/
+*/
contract PolicyManagerForStakingContractMock {
uint32 public secondsPerPeriod = 1;
@@ -110,7 +110,7 @@ contract PolicyManagerForStakingContractMock {
/**
* @notice Contract for staking contract tests
-**/
+*/
contract StakingInterfaceMockV1 {
function firstMethod() public pure {}
@@ -124,7 +124,7 @@ contract StakingInterfaceMockV1 {
/**
* @notice Contract for staking contract tests
-**/
+*/
contract StakingInterfaceMockV2 {
function () external payable {
@@ -145,7 +145,7 @@ contract StakingInterfaceMockV2 {
/**
* @dev Interface that could be destroyed by selfdestruct
-**/
+*/
contract DestroyableStakingInterface {
function method() public pure returns (uint256) {
diff --git a/tests/blockchain/eth/contracts/contracts/StakingEscrowTestSet.sol b/tests/blockchain/eth/contracts/contracts/StakingEscrowTestSet.sol
index 5bcf11faf..b6a5d3018 100644
--- a/tests/blockchain/eth/contracts/contracts/StakingEscrowTestSet.sol
+++ b/tests/blockchain/eth/contracts/contracts/StakingEscrowTestSet.sol
@@ -7,7 +7,7 @@ import "contracts/NuCypherToken.sol";
/**
* @notice Upgrade to this contract must lead to fail
-**/
+*/
contract StakingEscrowBad is StakingEscrow {
constructor(
@@ -45,7 +45,7 @@ contract StakingEscrowBad is StakingEscrow {
/**
* @notice Contract for testing upgrading the StakingEscrow contract
-**/
+*/
contract StakingEscrowV2Mock is StakingEscrow {
uint256 public valueToCheck;
@@ -97,7 +97,7 @@ contract StakingEscrowV2Mock is StakingEscrow {
/**
* @notice Contract for testing staking escrow contract
-**/
+*/
contract PolicyManagerForStakingEscrowMock {
StakingEscrow public escrow;
@@ -113,21 +113,21 @@ contract PolicyManagerForStakingEscrowMock {
/**
* @notice Update node info
- **/
+ */
function updateReward(address _node, uint16 _period) external {
nodes[_node].push(_period);
}
/**
* @notice Get length of array
- **/
+ */
function getPeriodsLength(address _node) public view returns (uint256) {
return nodes[_node].length;
}
/**
* @notice Get period info
- **/
+ */
function getPeriod(address _node, uint256 _index) public view returns (uint16) {
return nodes[_node][_index];
}
@@ -137,7 +137,7 @@ contract PolicyManagerForStakingEscrowMock {
/**
* @notice Contract for testing staking escrow contract
-**/
+*/
contract AdjudicatorForStakingEscrowMock {
StakingEscrow public escrow;
@@ -160,7 +160,7 @@ contract AdjudicatorForStakingEscrowMock {
/**
* @notice Intermediary contract for testing worker
-**/
+*/
contract Intermediary {
NuCypherToken token;
@@ -189,7 +189,7 @@ contract Intermediary {
/**
* @notice Contract for testing staking escrow contract
-**/
+*/
contract WorkLockForStakingEscrowMock {
StakingEscrow public escrow;
diff --git a/tests/blockchain/eth/contracts/contracts/WorkLockTestSet.sol b/tests/blockchain/eth/contracts/contracts/WorkLockTestSet.sol
index afc8bf3d5..ca7b2776d 100644
--- a/tests/blockchain/eth/contracts/contracts/WorkLockTestSet.sol
+++ b/tests/blockchain/eth/contracts/contracts/WorkLockTestSet.sol
@@ -6,7 +6,7 @@ import "contracts/NuCypherToken.sol";
/**
* @notice Contract for using in WorkLock tests
-**/
+*/
contract StakingEscrowForWorkLockMock {
struct StakerInfo {
diff --git a/tests/blockchain/eth/contracts/contracts/proxy/BadContracts.sol b/tests/blockchain/eth/contracts/contracts/proxy/BadContracts.sol
index 765fbd76b..6443e5296 100644
--- a/tests/blockchain/eth/contracts/contracts/proxy/BadContracts.sol
+++ b/tests/blockchain/eth/contracts/contracts/proxy/BadContracts.sol
@@ -7,7 +7,7 @@ import "contracts/proxy/Upgradeable.sol";
/**
* @dev This contract can't be target for dispatcher because missed `previousTarget`
-**/
+*/
contract BadDispatcherStorage {
address public owner;
@@ -24,7 +24,7 @@ contract BadDispatcherStorage {
/**
* @dev Upgrade to this contract will fail because added `fakeValue`
-**/
+*/
contract ContractV2BadStorage is Upgradeable {
// TODO can't catch such a violation
@@ -59,7 +59,7 @@ contract ContractV2BadStorage is Upgradeable {
/**
* @dev Upgrade to this contract will fail because `verifyState` is broken
-**/
+*/
contract ContractV2BadVerifyState is ContractV1(1) {
function verifyState(address) public {
diff --git a/tests/blockchain/eth/contracts/contracts/proxy/ContractV1.sol b/tests/blockchain/eth/contracts/contracts/proxy/ContractV1.sol
index cc270cf6a..3d16acc93 100644
--- a/tests/blockchain/eth/contracts/contracts/proxy/ContractV1.sol
+++ b/tests/blockchain/eth/contracts/contracts/proxy/ContractV1.sol
@@ -6,7 +6,7 @@ import "contracts/proxy/Upgradeable.sol";
/**
* @dev Base contract for testing upgrading using dispatcher
-**/
+*/
contract ContractV1 is Upgradeable {
event EventV1(uint256 value);
diff --git a/tests/blockchain/eth/contracts/contracts/proxy/ContractV2.sol b/tests/blockchain/eth/contracts/contracts/proxy/ContractV2.sol
index 601bea4ad..49a2fed7d 100644
--- a/tests/blockchain/eth/contracts/contracts/proxy/ContractV2.sol
+++ b/tests/blockchain/eth/contracts/contracts/proxy/ContractV2.sol
@@ -6,7 +6,7 @@ import "contracts/proxy/Upgradeable.sol";
/**
* @dev Extension of the contract using valid storage variables
-**/
+*/
contract ContractV2 is Upgradeable {
event EventV2(uint8 value);
@@ -176,7 +176,7 @@ contract ContractV2 is Upgradeable {
/**
* @dev Get array by one parameter.
- **/
+ */
function delegateGetArray(
address _target,
string memory _signature,
diff --git a/tests/blockchain/eth/contracts/contracts/proxy/ContractV4.sol b/tests/blockchain/eth/contracts/contracts/proxy/ContractV4.sol
index b10f221c6..e74d1d200 100644
--- a/tests/blockchain/eth/contracts/contracts/proxy/ContractV4.sol
+++ b/tests/blockchain/eth/contracts/contracts/proxy/ContractV4.sol
@@ -10,7 +10,7 @@ import "contracts/proxy/Upgradeable.sol";
* This demonstrates how to mitigate possible changes in the compiler while using the proxy pattern
* Many methods are not optimized on purpose to increase readability
* see https://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
-**/
+*/
contract ContractV4 is Upgradeable {
// slot allocation costs nothing
diff --git a/tests/blockchain/eth/contracts/contracts/proxy/Destroyable.sol b/tests/blockchain/eth/contracts/contracts/proxy/Destroyable.sol
index 8d46a35d5..d95b15340 100644
--- a/tests/blockchain/eth/contracts/contracts/proxy/Destroyable.sol
+++ b/tests/blockchain/eth/contracts/contracts/proxy/Destroyable.sol
@@ -6,7 +6,7 @@ import "contracts/proxy/Upgradeable.sol";
/**
* @dev Contract that could be destroyed by selfdestruct
-**/
+*/
contract Destroyable is Upgradeable {
uint256 public constructorValue;
diff --git a/tests/blockchain/eth/contracts/test_contracts_upgradeability.py b/tests/blockchain/eth/contracts/test_contracts_upgradeability.py
new file mode 100644
index 000000000..8cfb83a76
--- /dev/null
+++ b/tests/blockchain/eth/contracts/test_contracts_upgradeability.py
@@ -0,0 +1,144 @@
+"""
+This file is part of nucypher.
+
+nucypher 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.
+
+nucypher 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 nucypher. If not, see .
+"""
+import os
+
+import pytest
+import requests
+from eth_utils import keccak
+
+from nucypher.blockchain.eth.deployers import NucypherTokenDeployer, StakingEscrowDeployer, PolicyManagerDeployer, \
+ AdjudicatorDeployer, BaseContractDeployer, UpgradeableContractMixin, DispatcherDeployer
+from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory, BlockchainDeployerInterface
+from nucypher.blockchain.eth.registry import InMemoryContractRegistry, BaseContractRegistry
+from nucypher.blockchain.eth.sol.compile import SolidityCompiler, SourceDirs
+from nucypher.crypto.powers import TransactingPower
+from nucypher.utilities.sandbox.blockchain import TesterBlockchain
+from nucypher.utilities.sandbox.constants import INSECURE_DEVELOPMENT_PASSWORD, STAKING_ESCROW_DEPLOYMENT_SECRET, \
+ POLICY_MANAGER_DEPLOYMENT_SECRET, ADJUDICATOR_DEPLOYMENT_SECRET
+
+USER = "nucypher"
+REPO = "nucypher"
+BRANCH = "master"
+GITHUB_SOURCE_LINK = f"https://api.github.com/repos/{USER}/{REPO}/contents/nucypher/blockchain/eth/sol/source?ref={BRANCH}"
+
+
+def download_github_dir(source_link: str, target_folder: str):
+ response = requests.get(source_link)
+ if response.status_code != 200:
+ error = f"Failed to call api {source_link} with status code {response.status_code}"
+ raise RuntimeError(error)
+
+ for content in response.json():
+ path = os.path.join(target_folder, content["name"])
+ if content["type"] == "dir":
+ os.mkdir(path)
+ download_github_dir(content["url"], path)
+ else:
+ download_github_file(content["download_url"], path)
+
+
+def download_github_file(source_link: str, target_folder: str):
+ response = requests.get(source_link)
+ if response.status_code != 200:
+ error = f"Failed to call api {source_link} with status code {response.status_code}"
+ raise RuntimeError(error)
+
+ raw_data = response.content
+ with open(target_folder, 'wb') as registry_file:
+ registry_file.seek(0)
+ registry_file.write(raw_data)
+ registry_file.truncate()
+
+
+# Constructor parameters overrides for previous versions if needed
+# 'None' value removes arg from list of constructor parameters
+CONSTRUCTOR_OVERRIDES = {
+ # Test example
+ StakingEscrowDeployer.contract_name: {"v0.0.0": {"_hoursPerPeriod": 1}}
+}
+
+
+def deploy_earliest_contract(blockchain_interface: BlockchainDeployerInterface,
+ deployer: BaseContractDeployer,
+ secret: str):
+ contract_name = deployer.contract_name
+ earliest_version, _data = blockchain_interface.find_raw_contract_data(contract_name, "earliest")
+ try:
+ overrides = CONSTRUCTOR_OVERRIDES[contract_name][earliest_version]
+ except KeyError:
+ overrides = dict()
+
+ deployer.deploy(secret_hash=keccak(text=secret), contract_version=earliest_version, **overrides)
+
+
+def upgrade_to_latest_contract(deployer, secret: str):
+ old_secret = bytes(secret, encoding='utf-8')
+ new_secret_hash = keccak(b'new' + old_secret)
+ deployer.upgrade(existing_secret_plaintext=old_secret,
+ new_secret_hash=new_secret_hash,
+ contract_version="latest")
+
+
+@pytest.mark.slow
+def test_upgradeability(temp_dir_path, token_economics):
+ # Prepare remote source for compilation
+ download_github_dir(GITHUB_SOURCE_LINK, temp_dir_path)
+ solidity_compiler = SolidityCompiler(source_dirs=[SourceDirs(SolidityCompiler.default_contract_dir()),
+ SourceDirs(temp_dir_path)])
+
+ # Prepare the blockchain
+ blockchain_interface = BlockchainDeployerInterface(provider_uri='tester://pyevm/2', compiler=solidity_compiler)
+ blockchain_interface.connect()
+ origin = blockchain_interface.client.accounts[0]
+ BlockchainInterfaceFactory.register_interface(interface=blockchain_interface)
+ blockchain_interface.transacting_power = TransactingPower(password=INSECURE_DEVELOPMENT_PASSWORD, account=origin)
+ blockchain_interface.transacting_power.activate()
+
+ # Check contracts with multiple versions
+ raw_contracts = blockchain_interface._raw_contract_cache
+ contract_name = AdjudicatorDeployer.contract_name
+ test_adjudicator = len(raw_contracts[contract_name]) > 1
+ contract_name = StakingEscrowDeployer.contract_name
+ test_staking_escrow = len(raw_contracts[contract_name]) > 1
+ contract_name = PolicyManagerDeployer.contract_name
+ test_policy_manager = len(raw_contracts[contract_name]) > 1
+
+ if not test_adjudicator and not test_staking_escrow and not test_policy_manager:
+ return
+
+ # Prepare master version of contracts and upgrade to the latest
+ registry = InMemoryContractRegistry()
+
+ token_deployer = NucypherTokenDeployer(registry=registry, deployer_address=origin)
+ token_deployer.deploy()
+
+ staking_escrow_deployer = StakingEscrowDeployer(registry=registry, deployer_address=origin)
+ deploy_earliest_contract(blockchain_interface, staking_escrow_deployer, secret=STAKING_ESCROW_DEPLOYMENT_SECRET)
+ assert staking_escrow_deployer.contract.functions.secondsPerPeriod().call() == 3600
+ if test_staking_escrow:
+ upgrade_to_latest_contract(staking_escrow_deployer, secret=STAKING_ESCROW_DEPLOYMENT_SECRET)
+ assert staking_escrow_deployer.contract.functions.secondsPerPeriod().call() == token_economics.seconds_per_period
+
+ if test_policy_manager:
+ policy_manager_deployer = PolicyManagerDeployer(registry=registry, deployer_address=origin)
+ deploy_earliest_contract(blockchain_interface, policy_manager_deployer, secret=POLICY_MANAGER_DEPLOYMENT_SECRET)
+ upgrade_to_latest_contract(policy_manager_deployer, secret=POLICY_MANAGER_DEPLOYMENT_SECRET)
+
+ if test_adjudicator:
+ adjudicator_deployer = AdjudicatorDeployer(registry=registry, deployer_address=origin)
+ deploy_earliest_contract(blockchain_interface, adjudicator_deployer, secret=ADJUDICATOR_DEPLOYMENT_SECRET)
+ upgrade_to_latest_contract(adjudicator_deployer, secret=ADJUDICATOR_DEPLOYMENT_SECRET)
diff --git a/tests/blockchain/eth/entities/deployers/test_interdeployer_integration.py b/tests/blockchain/eth/entities/deployers/test_interdeployer_integration.py
index f9bae2416..8b058f112 100644
--- a/tests/blockchain/eth/entities/deployers/test_interdeployer_integration.py
+++ b/tests/blockchain/eth/entities/deployers/test_interdeployer_integration.py
@@ -45,10 +45,10 @@ def test_deploy_ethereum_contracts(testerchain,
with pytest.raises(BaseContractDeployer.ContractDeploymentError):
assert token_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
- assert not token_deployer.is_deployed
+ assert not token_deployer.is_deployed()
token_deployer.deploy(progress=deployment_progress)
- assert token_deployer.is_deployed
+ assert token_deployer.is_deployed()
assert len(token_deployer.contract_address) == 42
token_agent = NucypherTokenAgent(registry=test_registry)
@@ -70,10 +70,10 @@ def test_deploy_ethereum_contracts(testerchain,
with pytest.raises(BaseContractDeployer.ContractDeploymentError):
assert staking_escrow_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
- assert not staking_escrow_deployer.is_deployed
+ assert not staking_escrow_deployer.is_deployed()
staking_escrow_deployer.deploy(secret_hash=keccak(stakers_escrow_secret), progress=deployment_progress)
- assert staking_escrow_deployer.is_deployed
+ assert staking_escrow_deployer.is_deployed()
assert len(staking_escrow_deployer.contract_address) == 42
staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=test_registry)
@@ -97,10 +97,10 @@ def test_deploy_ethereum_contracts(testerchain,
with pytest.raises(BaseContractDeployer.ContractDeploymentError):
assert policy_manager_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
- assert not policy_manager_deployer.is_deployed
+ assert not policy_manager_deployer.is_deployed()
policy_manager_deployer.deploy(secret_hash=keccak(policy_manager_secret), progress=deployment_progress)
- assert policy_manager_deployer.is_deployed
+ assert policy_manager_deployer.is_deployed()
assert len(policy_manager_deployer.contract_address) == 42
policy_agent = policy_manager_deployer.make_agent()
@@ -124,10 +124,10 @@ def test_deploy_ethereum_contracts(testerchain,
with pytest.raises(BaseContractDeployer.ContractDeploymentError):
assert adjudicator_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
- assert not adjudicator_deployer.is_deployed
+ assert not adjudicator_deployer.is_deployed()
adjudicator_deployer.deploy(secret_hash=keccak(adjudicator_secret), progress=deployment_progress)
- assert adjudicator_deployer.is_deployed
+ assert adjudicator_deployer.is_deployed()
assert len(adjudicator_deployer.contract_address) == 42
adjudicator_agent = adjudicator_deployer.make_agent()
diff --git a/tests/blockchain/eth/entities/deployers/test_policy_manager_deployer.py b/tests/blockchain/eth/entities/deployers/test_policy_manager_deployer.py
index 4d48576d2..53876acdd 100644
--- a/tests/blockchain/eth/entities/deployers/test_policy_manager_deployer.py
+++ b/tests/blockchain/eth/entities/deployers/test_policy_manager_deployer.py
@@ -83,7 +83,7 @@ def test_policy_manager_has_dispatcher(policy_manager_deployer, testerchain, tes
# Let's get the "bare" PolicyManager contract (i.e., unwrapped, no dispatcher)
existing_bare_contract = testerchain.get_contract_by_name(registry=test_registry,
- name=policy_manager_deployer.contract_name,
+ contract_name=policy_manager_deployer.contract_name,
proxy_name=DispatcherDeployer.contract_name,
use_proxy_address=False)
@@ -106,7 +106,7 @@ def test_upgrade(testerchain, test_registry):
deployer_address=testerchain.etherbase_account)
bare_contract = testerchain.get_contract_by_name(registry=test_registry,
- name=PolicyManagerDeployer.contract_name,
+ contract_name=PolicyManagerDeployer.contract_name,
proxy_name=DispatcherDeployer.contract_name,
use_proxy_address=False)
old_address = bare_contract.address
@@ -116,10 +116,11 @@ def test_upgrade(testerchain, test_registry):
new_secret_hash=new_secret_hash)
receipts = deployer.upgrade(existing_secret_plaintext=old_secret,
- new_secret_hash=new_secret_hash)
+ new_secret_hash=new_secret_hash,
+ ignore_deployed=True)
bare_contract = testerchain.get_contract_by_name(registry=test_registry,
- name=PolicyManagerDeployer.contract_name,
+ contract_name=PolicyManagerDeployer.contract_name,
proxy_name=DispatcherDeployer.contract_name,
use_proxy_address=False)
@@ -146,7 +147,8 @@ def test_rollback(testerchain, test_registry):
# Let's do one more upgrade
receipts = deployer.upgrade(existing_secret_plaintext=old_secret,
- new_secret_hash=new_secret_hash)
+ new_secret_hash=new_secret_hash,
+ ignore_deployed=True)
for title, receipt in receipts.items():
assert receipt['status'] == 1
diff --git a/tests/blockchain/eth/entities/deployers/test_preallocation_escrow_deployer.py b/tests/blockchain/eth/entities/deployers/test_preallocation_escrow_deployer.py
index d58a75a62..83e0077d6 100644
--- a/tests/blockchain/eth/entities/deployers/test_preallocation_escrow_deployer.py
+++ b/tests/blockchain/eth/entities/deployers/test_preallocation_escrow_deployer.py
@@ -80,7 +80,7 @@ def test_deploy_multiple_preallocations(testerchain, test_registry):
testerchain = testerchain
deployer_account = testerchain.etherbase_account
- router = testerchain.get_contract_by_name(registry=test_registry, name=StakingInterfaceRouterDeployer.contract_name)
+ router = testerchain.get_contract_by_name(registry=test_registry, contract_name=StakingInterfaceRouterDeployer.contract_name)
router_address = router.address
for index in range(NUMBER_OF_PREALLOCATIONS):
deployer = PreallocationEscrowDeployer(deployer_address=deployer_account, registry=test_registry)
@@ -108,10 +108,10 @@ def test_upgrade_staking_interface(testerchain, test_registry):
old_secret = INSECURE_DEPLOYMENT_SECRET_PLAINTEXT
new_secret = 'new' + STAKING_INTERFACE_DEPLOYMENT_SECRET
new_secret_hash = keccak_digest(new_secret.encode())
- router = testerchain.get_contract_by_name(registry=test_registry, name=StakingInterfaceRouterDeployer.contract_name)
+ router = testerchain.get_contract_by_name(registry=test_registry, contract_name=StakingInterfaceRouterDeployer.contract_name)
contract = testerchain.get_contract_by_name(registry=test_registry,
- name=StakingInterfaceDeployer.contract_name,
+ contract_name=StakingInterfaceDeployer.contract_name,
proxy_name=StakingInterfaceRouterDeployer.contract_name,
use_proxy_address=False)
@@ -122,7 +122,8 @@ def test_upgrade_staking_interface(testerchain, test_registry):
registry=test_registry)
receipts = staking_interface_deployer.upgrade(existing_secret_plaintext=old_secret,
- new_secret_hash=new_secret_hash)
+ new_secret_hash=new_secret_hash,
+ ignore_deployed=True)
assert len(receipts) == 2
@@ -135,7 +136,7 @@ def test_upgrade_staking_interface(testerchain, test_registry):
new_target = router.functions.target().call()
contract = testerchain.get_contract_by_name(registry=test_registry,
- name=StakingInterfaceDeployer.contract_name,
+ contract_name=StakingInterfaceDeployer.contract_name,
proxy_name=StakingInterfaceRouterDeployer.contract_name,
use_proxy_address=False)
assert new_target == contract.address
diff --git a/tests/blockchain/eth/entities/deployers/test_staking_escrow_deployer.py b/tests/blockchain/eth/entities/deployers/test_staking_escrow_deployer.py
index 5bf6e2aa6..29eb71629 100644
--- a/tests/blockchain/eth/entities/deployers/test_staking_escrow_deployer.py
+++ b/tests/blockchain/eth/entities/deployers/test_staking_escrow_deployer.py
@@ -66,7 +66,7 @@ def test_staking_escrow_has_dispatcher(staking_escrow_deployer, testerchain, tes
# Let's get the "bare" StakingEscrow contract (i.e., unwrapped, no dispatcher)
existing_bare_contract = testerchain.get_contract_by_name(registry=test_registry,
- name=staking_escrow_deployer.contract_name,
+ contract_name=staking_escrow_deployer.contract_name,
proxy_name=DispatcherDeployer.contract_name,
use_proxy_address=False)
@@ -92,7 +92,9 @@ def test_upgrade(testerchain, test_registry, token_economics):
with pytest.raises(deployer.ContractDeploymentError):
deployer.upgrade(existing_secret_plaintext=wrong_secret, new_secret_hash=new_secret_hash)
- receipts = deployer.upgrade(existing_secret_plaintext=old_secret, new_secret_hash=new_secret_hash)
+ receipts = deployer.upgrade(existing_secret_plaintext=old_secret,
+ new_secret_hash=new_secret_hash,
+ ignore_deployed=True)
for title, receipt in receipts.items():
assert receipt['status'] == 1
@@ -108,7 +110,9 @@ def test_rollback(testerchain, test_registry):
current_target = staking_agent.contract.functions.target().call()
# Let's do one more upgrade
- receipts = deployer.upgrade(existing_secret_plaintext=old_secret, new_secret_hash=new_secret_hash)
+ receipts = deployer.upgrade(existing_secret_plaintext=old_secret,
+ new_secret_hash=new_secret_hash,
+ ignore_deployed=True)
for title, receipt in receipts.items():
assert receipt['status'] == 1
@@ -145,7 +149,7 @@ def test_deploy_bare_upgradeable_contract_deployment(testerchain, test_registry,
old_number_of_enrollments = enrolled_names.count(StakingEscrowDeployer.contract_name)
old_number_of_proxy_enrollments = enrolled_names.count(StakingEscrowDeployer._proxy_deployer.contract_name)
- receipts = deployer.deploy(initial_deployment=False)
+ receipts = deployer.deploy(initial_deployment=False, ignore_deployed=True)
for title, receipt in receipts.items():
assert receipt['status'] == 1
diff --git a/tests/blockchain/eth/interfaces/contracts/multiversion/v1/VersionTest.sol b/tests/blockchain/eth/interfaces/contracts/multiversion/v1/VersionTest.sol
new file mode 100644
index 000000000..128e8ee6a
--- /dev/null
+++ b/tests/blockchain/eth/interfaces/contracts/multiversion/v1/VersionTest.sol
@@ -0,0 +1,10 @@
+pragma solidity ^0.5.3;
+
+
+/**
+* @notice Test extracting version number from dev docs
+* @dev |v1.1.4|
+*/
+contract VersionTest {
+ uint16 public constant VERSION = 1;
+}
diff --git a/tests/blockchain/eth/interfaces/contracts/multiversion/v2/VersionTest.sol b/tests/blockchain/eth/interfaces/contracts/multiversion/v2/VersionTest.sol
new file mode 100644
index 000000000..72b9c7567
--- /dev/null
+++ b/tests/blockchain/eth/interfaces/contracts/multiversion/v2/VersionTest.sol
@@ -0,0 +1,10 @@
+pragma solidity ^0.5.3;
+
+
+/**
+* @notice Test extracting version number from dev docs
+* @dev |v1.2.3|
+*/
+contract VersionTest {
+ uint16 public constant VERSION = 2;
+}
diff --git a/tests/blockchain/eth/interfaces/test_chains.py b/tests/blockchain/eth/interfaces/test_chains.py
index f14234950..d6e0ec0ff 100644
--- a/tests/blockchain/eth/interfaces/test_chains.py
+++ b/tests/blockchain/eth/interfaces/test_chains.py
@@ -14,26 +14,29 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see .
"""
-
+import os
+from os.path import dirname, abspath
import pytest
-from nucypher.blockchain.eth.interfaces import BlockchainDeployerInterface
+from nucypher.blockchain.eth.interfaces import BlockchainDeployerInterface, BlockchainInterfaceFactory
from nucypher.blockchain.eth.registry import InMemoryContractRegistry
# Prevents TesterBlockchain to be picked up by py.test as a test class
+from nucypher.blockchain.eth.sol.compile import SolidityCompiler, SourceDirs
+from nucypher.crypto.powers import TransactingPower
from nucypher.utilities.sandbox.blockchain import TesterBlockchain as _TesterBlockchain
from nucypher.utilities.sandbox.constants import (
DEVELOPMENT_ETH_AIRDROP_AMOUNT,
NUMBER_OF_ETH_TEST_ACCOUNTS,
NUMBER_OF_STAKERS_IN_BLOCKCHAIN_TESTS,
NUMBER_OF_URSULAS_IN_BLOCKCHAIN_TESTS,
- TEST_PROVIDER_URI
-)
+ TEST_PROVIDER_URI,
+ INSECURE_DEVELOPMENT_PASSWORD)
@pytest.fixture()
def another_testerchain(solidity_compiler):
- testerchain = _TesterBlockchain(eth_airdrop=True, free_transactions=True, light=True)
+ testerchain = _TesterBlockchain(eth_airdrop=True, free_transactions=True, light=True, compiler=solidity_compiler)
testerchain.deployer_address = testerchain.etherbase_account
assert testerchain.is_light
yield testerchain
@@ -86,3 +89,71 @@ def test_testerchain_creation(testerchain, another_testerchain):
tx = {'to': etherbase, 'from': account, 'value': 100}
txhash = chain.client.send_transaction(tx)
_receipt = chain.wait_for_receipt(txhash)
+
+
+def test_multiversion_contract():
+ # Prepare compiler
+ base_dir = os.path.join(dirname(abspath(__file__)), "contracts", "multiversion")
+ v1_dir = os.path.join(base_dir, "v1")
+ v2_dir = os.path.join(base_dir, "v2")
+ root_dir = SolidityCompiler.default_contract_dir()
+ solidity_compiler = SolidityCompiler(source_dirs=[SourceDirs(root_dir, {v2_dir}),
+ SourceDirs(root_dir, {v1_dir})])
+
+ # Prepare chain
+ blockchain_interface = BlockchainDeployerInterface(provider_uri='tester://pyevm/2', compiler=solidity_compiler)
+ blockchain_interface.connect()
+ origin = blockchain_interface.client.accounts[0]
+ blockchain_interface.transacting_power = TransactingPower(password=INSECURE_DEVELOPMENT_PASSWORD, account=origin)
+ blockchain_interface.transacting_power.activate()
+
+ # Searching both contract through raw data
+ contract_name = "VersionTest"
+ requested_version = "v1.2.3"
+ version, _data = blockchain_interface.find_raw_contract_data(contract_name=contract_name,
+ requested_version=requested_version)
+ assert version == requested_version
+ version, _data = blockchain_interface.find_raw_contract_data(contract_name=contract_name,
+ requested_version="latest")
+ assert version == requested_version
+
+ requested_version = "v1.1.4"
+ version, _data = blockchain_interface.find_raw_contract_data(contract_name=contract_name,
+ requested_version=requested_version)
+ assert version == requested_version
+ version, _data = blockchain_interface.find_raw_contract_data(contract_name=contract_name,
+ requested_version="earliest")
+ assert version == requested_version
+
+ # Deploy different contracts and check their versions
+ registry = InMemoryContractRegistry()
+ contract, receipt = blockchain_interface.deploy_contract(deployer_address=origin,
+ registry=registry,
+ contract_name=contract_name,
+ contract_version="v1.1.4")
+ assert contract.version == "v1.1.4"
+ assert contract.functions.VERSION().call() == 1
+ contract, receipt = blockchain_interface.deploy_contract(deployer_address=origin,
+ registry=registry,
+ contract_name=contract_name,
+ contract_version="earliest")
+ assert contract.version == "v1.1.4"
+ assert contract.functions.VERSION().call() == 1
+
+ contract, receipt = blockchain_interface.deploy_contract(deployer_address=origin,
+ registry=registry,
+ contract_name=contract_name,
+ contract_version="v1.2.3")
+ assert contract.version == "v1.2.3"
+ assert contract.functions.VERSION().call() == 2
+ contract, receipt = blockchain_interface.deploy_contract(deployer_address=origin,
+ registry=registry,
+ contract_name=contract_name,
+ contract_version="latest")
+ assert contract.version == "v1.2.3"
+ assert contract.functions.VERSION().call() == 2
+ contract, receipt = blockchain_interface.deploy_contract(deployer_address=origin,
+ registry=registry,
+ contract_name=contract_name)
+ assert contract.version == "v1.2.3"
+ assert contract.functions.VERSION().call() == 2
diff --git a/tests/blockchain/eth/interfaces/test_registry.py b/tests/blockchain/eth/interfaces/test_registry.py
index 6b125ad4a..fb298ecc3 100644
--- a/tests/blockchain/eth/interfaces/test_registry.py
+++ b/tests/blockchain/eth/interfaces/test_registry.py
@@ -47,28 +47,32 @@ def test_contract_registry(tempfile_path):
test_name = 'TestContract'
test_addr = '0xDEADBEEF'
test_abi = ['fake', 'data']
+ test_version = "some_version"
test_registry.enroll(contract_name=test_name,
contract_address=test_addr,
- contract_abi=test_abi)
+ contract_abi=test_abi,
+ contract_version=test_version)
# Search by name...
contract_records = test_registry.search(contract_name=test_name)
assert len(contract_records) == 1, 'More than one record for {}'.format(test_name)
- assert len(contract_records[0]) == 3, 'Registry record is the wrong length'
- name, address, abi = contract_records[0]
+ assert len(contract_records[0]) == 4, 'Registry record is the wrong length'
+ name, version, address, abi = contract_records[0]
assert name == test_name
assert address == test_addr
assert abi == test_abi
+ assert version == test_version
# ...or by address
contract_record = test_registry.search(contract_address=test_addr)
- name, address, abi = contract_record
+ name, version, address, abi = contract_record
assert name == test_name
assert address == test_addr
assert abi == test_abi
+ assert version == test_version
# Check that searching for an unknown contract raises
with pytest.raises(BaseContractRegistry.UnknownContract):
diff --git a/tests/blockchain/eth/interfaces/test_solidity_compiler.py b/tests/blockchain/eth/interfaces/test_solidity_compiler.py
index 443b156a7..915525b31 100644
--- a/tests/blockchain/eth/interfaces/test_solidity_compiler.py
+++ b/tests/blockchain/eth/interfaces/test_solidity_compiler.py
@@ -14,9 +14,12 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see .
"""
-
+import os
+from os.path import dirname, abspath
from nucypher.blockchain.eth.deployers import NucypherTokenDeployer
+from nucypher.blockchain.eth.sol.compile import SolidityCompiler, SourceDirs
+from nucypher.utilities.sandbox.blockchain import TesterBlockchain
def test_nucypher_contract_compiled(testerchain, test_registry):
@@ -24,4 +27,41 @@ def test_nucypher_contract_compiled(testerchain, test_registry):
origin, *everybody_else = testerchain.client.accounts
token_contract_identifier = NucypherTokenDeployer(registry=test_registry, deployer_address=origin).contract_name
- assert token_contract_identifier in testerchain._BlockchainDeployerInterface__raw_contract_cache
+ assert token_contract_identifier in testerchain._raw_contract_cache
+ token_data = testerchain._raw_contract_cache[token_contract_identifier]
+ assert len(token_data) == 1
+ assert "v0.0.0" in token_data
+
+
+def test_multi_source_compilation(testerchain):
+ solidity_compiler = SolidityCompiler(source_dirs=[
+ (SolidityCompiler.default_contract_dir(), None),
+ (SolidityCompiler.default_contract_dir(), {TesterBlockchain.TEST_CONTRACTS_DIR})
+ ])
+ interfaces = solidity_compiler.compile()
+
+ # Remove AST because id in tree node depends on compilation scope
+ for contract_name, contract_data in interfaces.items():
+ for version, data in contract_data.items():
+ data.pop("ast")
+ raw_cache = testerchain._raw_contract_cache.copy()
+ for contract_name, contract_data in raw_cache.items():
+ for version, data in contract_data.items():
+ data.pop("ast")
+ assert interfaces == raw_cache
+
+
+def test_multi_versions():
+ base_dir = os.path.join(dirname(abspath(__file__)), "contracts", "multiversion")
+ v1_dir = os.path.join(base_dir, "v1")
+ v2_dir = os.path.join(base_dir, "v2")
+ root_dir = SolidityCompiler.default_contract_dir()
+ solidity_compiler = SolidityCompiler(source_dirs=[SourceDirs(root_dir, {v1_dir}),
+ SourceDirs(root_dir, {v2_dir})])
+ interfaces = solidity_compiler.compile()
+ assert "VersionTest" in interfaces
+ contract_data = interfaces["VersionTest"]
+ assert len(contract_data) == 2
+ assert "v1.2.3" in contract_data
+ assert "v1.1.4" in contract_data
+ assert contract_data["v1.2.3"]["devdoc"] != contract_data["v1.1.4"]["devdoc"]
diff --git a/tests/cli/test_deploy.py b/tests/cli/test_deploy.py
index e43ea7646..016e9c64e 100644
--- a/tests/cli/test_deploy.py
+++ b/tests/cli/test_deploy.py
@@ -32,19 +32,13 @@ def generate_insecure_secret() -> str:
return formatted_secret
-# TODO: Use temp module
-DEPLOYMENT_REGISTRY_FILEPATH = os.path.join('/', 'tmp', 'nucypher-test-autodeploy.json')
PLANNED_UPGRADES = 4
INSECURE_SECRETS = {v: generate_insecure_secret() for v in range(1, PLANNED_UPGRADES+1)}
@pytest.fixture(scope="module")
-def registry_filepath():
- if os.path.exists(DEPLOYMENT_REGISTRY_FILEPATH):
- os.remove(DEPLOYMENT_REGISTRY_FILEPATH)
- yield DEPLOYMENT_REGISTRY_FILEPATH
- if os.path.exists(DEPLOYMENT_REGISTRY_FILEPATH):
- os.remove(DEPLOYMENT_REGISTRY_FILEPATH)
+def registry_filepath(temp_dir_path):
+ return os.path.join(temp_dir_path, 'nucypher-test-autodeploy.json')
def test_nucypher_deploy_contracts(click_runner,
@@ -90,7 +84,7 @@ def test_nucypher_deploy_contracts(click_runner,
# Read several records
token_record, escrow_record, dispatcher_record, *other_records = registry_data
- registered_name, registered_address, registered_abi = token_record
+ registered_name, registered_version, registered_address, registered_abi = token_record
#
# Agency
@@ -101,6 +95,7 @@ def test_nucypher_deploy_contracts(click_runner,
assert token_agent.contract_name == registered_name
assert token_agent.registry_contract_name == registered_name
assert token_agent.contract_address == registered_address
+ assert token_agent.contract.version == registered_version
# Now show that we can use contract Agency and read from the blockchain
assert token_agent.get_balance() == 0
@@ -214,7 +209,7 @@ def test_upgrade_contracts(click_runner, registry_filepath, testerchain):
proxy_name = 'Dispatcher'
registry = LocalContractRegistry(filepath=registry_filepath)
- real_old_contract = testerchain.get_contract_by_name(name=contract_name,
+ real_old_contract = testerchain.get_contract_by_name(contract_name=contract_name,
registry=registry,
proxy_name=proxy_name,
use_proxy_address=False)
@@ -227,7 +222,7 @@ def test_upgrade_contracts(click_runner, registry_filepath, testerchain):
assert targeted_address == real_old_contract.address
# Assemble CLI command
- command = (cli_action, '--contract-name', contract_name, *base_command)
+ command = (cli_action, '--contract-name', contract_name, '--ignore-deployed', *base_command)
# Select upgrade interactive input scenario
current_version = version_tracker[contract_name]
@@ -268,8 +263,8 @@ def test_upgrade_contracts(click_runner, registry_filepath, testerchain):
assert len(records) == contract_enrollments, error
old, new = records[-2:] # Get the last two entries
- old_name, old_address, *abi = old # Previous version
- new_name, new_address, *abi = new # New version
+ old_name, _old_version, old_address, *abi = old # Previous version
+ new_name, _new_version, new_address, *abi = new # New version
assert old_address == real_old_contract.address
assert old_name == new_name # TODO: Inspect ABI / Move to different test.
@@ -319,8 +314,8 @@ def test_rollback(click_runner, testerchain, registry_filepath):
*old_records, v3, v4 = records
current_target, rollback_target = v4, v3
- _name, current_target_address, *abi = current_target
- _name, rollback_target_address, *abi = rollback_target
+ _name, _version, current_target_address, *abi = current_target
+ _name, _version, rollback_target_address, *abi = rollback_target
assert current_target_address != rollback_target_address
# Ensure the proxy targets the rollback target (previous version)
diff --git a/tests/cli/test_deploy_commands.py b/tests/cli/test_deploy_commands.py
index 8dd0bffed..b8b7a9e29 100644
--- a/tests/cli/test_deploy_commands.py
+++ b/tests/cli/test_deploy_commands.py
@@ -117,7 +117,8 @@ def test_bare_contract_deployment_to_alternate_registry(click_runner, test_regis
'--provider', TEST_PROVIDER_URI,
'--registry-infile', MOCK_REGISTRY_FILEPATH,
'--registry-outfile', ALTERNATE_REGISTRY_FILEPATH,
- '--poa')
+ '--poa',
+ '--ignore-deployed')
user_input = '0\n' + 'Y\n' + 'DEPLOY'
result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False)