diff --git a/nucypher/blockchain/eth/deployers.py b/nucypher/blockchain/eth/deployers.py index 6f748bcf4..cd2b1e166 100644 --- a/nucypher/blockchain/eth/deployers.py +++ b/nucypher/blockchain/eth/deployers.py @@ -570,9 +570,6 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna confirmations: int = 0, **overrides): constructor_kwargs = { - "_genesisHoursPerPeriod": self.economics.genesis_hours_per_period, - "_hoursPerPeriod": self.economics.hours_per_period, - "_minLockedPeriods": self.economics.minimum_locked_periods, "_minAllowableLockedTokens": self.economics.minimum_allowed_locked, "_maxAllowableLockedTokens": self.economics.maximum_allowed_locked } @@ -597,27 +594,11 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna gas_limit: int = None, confirmations: int = 0, **overrides): - args = self.economics.staking_deployment_parameters - constructor_kwargs = { - "_genesisHoursPerPeriod": args[0], - "_hoursPerPeriod": args[1], - "_issuanceDecayCoefficient": args[2], - "_lockDurationCoefficient1": args[3], - "_lockDurationCoefficient2": args[4], - "_maximumRewardedPeriods": args[5], - "_firstPhaseTotalSupply": args[6], - "_firstPhaseMaxIssuance": args[7], - "_minLockedPeriods": args[8], - "_minAllowableLockedTokens": args[9], - "_maxAllowableLockedTokens": args[10], - "_minWorkerPeriods": args[11] - } + constructor_kwargs = {} constructor_kwargs.update(overrides) constructor_kwargs = {k: v for k, v in constructor_kwargs.items() if v is not None} # Force use of the contract addresses from the registry constructor_kwargs.update({"_token": self.token_contract.address, - "_policyManager": self.policy_manager.address, - "_adjudicator": self.adjudicator.address, "_workLock": self.worklock.address if self.worklock is not None else NULL_ADDRESS}) the_escrow_contract, deploy_receipt = self.blockchain.deploy_contract( transacting_power, diff --git a/nucypher/blockchain/eth/sol/source/contracts/StakingEscrow.sol b/nucypher/blockchain/eth/sol/source/contracts/StakingEscrow.sol index b6482e71b..499176352 100644 --- a/nucypher/blockchain/eth/sol/source/contracts/StakingEscrow.sol +++ b/nucypher/blockchain/eth/sol/source/contracts/StakingEscrow.sol @@ -149,13 +149,13 @@ contract StakingEscrow is Upgradeable, IERC900History { NuCypherToken public immutable token; WorkLockInterface public immutable workLock; - uint128 previousPeriodSupply; // outdated - uint128 currentPeriodSupply; // outdated - uint16 currentMintingPeriod; // outdated + uint128 public previousPeriodSupply; // outdated + uint128 public currentPeriodSupply; // outdated + uint16 public currentMintingPeriod; // outdated mapping (address => StakerInfo) public stakerInfo; address[] public stakers; - mapping (address => address) stakerFromWorker; // outdated + mapping (address => address) public stakerFromWorker; // outdated mapping (uint16 => uint256) stub1; // former slot for lockedPerPeriod uint128[] public balanceHistory; diff --git a/tests/contracts/contracts/UpgradeabilityTestSet.sol b/tests/contracts/contracts/UpgradeabilityTestSet.sol new file mode 100644 index 000000000..31cc04126 --- /dev/null +++ b/tests/contracts/contracts/UpgradeabilityTestSet.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.7.0; + + +contract OldPolicyManagerMock { + uint32 public immutable secondsPerPeriod = 1 hours; + + function register(address _node, uint16 _period) external {} +} + + +contract OldAdjudicatorMock { + uint256 public immutable rewardCoefficient = 1; +} diff --git a/tests/contracts/test_contracts_upgradeability.py b/tests/contracts/test_contracts_upgradeability.py index 54afb4330..8b26359b2 100644 --- a/tests/contracts/test_contracts_upgradeability.py +++ b/tests/contracts/test_contracts_upgradeability.py @@ -19,9 +19,13 @@ import contextlib from pathlib import Path import requests +from eth_utils import to_wei + from constant_sorrow import constants from web3.exceptions import ValidationError +from nucypher.blockchain.economics import BaseEconomics +from nucypher.blockchain.eth.agents import StakingEscrowAgent, WorkLockAgent from nucypher.blockchain.eth.deployers import ( AdjudicatorDeployer, BaseContractDeployer, @@ -31,14 +35,14 @@ from nucypher.blockchain.eth.deployers import ( WorklockDeployer ) from nucypher.blockchain.eth.interfaces import BlockchainDeployerInterface, BlockchainInterfaceFactory -from nucypher.blockchain.eth.registry import InMemoryContractRegistry +from nucypher.blockchain.eth.registry import InMemoryContractRegistry, BaseContractRegistry from nucypher.blockchain.eth.signers.software import Web3Signer -from nucypher.blockchain.eth.sol.compile.constants import SOLIDITY_SOURCE_ROOT +from nucypher.blockchain.eth.sol.compile.constants import SOLIDITY_SOURCE_ROOT, TEST_SOLIDITY_SOURCE_ROOT from nucypher.blockchain.eth.sol.compile.types import SourceBundle from nucypher.crypto.powers import TransactingPower from tests.constants import INSECURE_DEVELOPMENT_PASSWORD from tests.fixtures import make_token_economics -from tests.utils.blockchain import free_gas_price_strategy +from tests.utils.blockchain import free_gas_price_strategy, TesterBlockchain USER = "nucypher" REPO = "nucypher" @@ -78,21 +82,46 @@ def download_github_file(source_link: str, target_folder: Path): registry_file.truncate() +def parameters_v611(blockchain_interface: BlockchainDeployerInterface, + transacting_power: TransactingPower, + deployer: BaseContractDeployer): + policy_manager_mock, _ = blockchain_interface.deploy_contract( + transacting_power, + deployer.registry, + "OldPolicyManagerMock" + ) + adjudicator_mock, _ = blockchain_interface.deploy_contract( + transacting_power, + deployer.registry, + "OldAdjudicatorMock" + ) + parameters = { + "_genesisHoursPerPeriod": 1, + "_hoursPerPeriod": 1, + "_issuanceDecayCoefficient": 1, + "_lockDurationCoefficient1": 1, + "_lockDurationCoefficient2": 2, + "_maximumRewardedPeriods": 1, + "_firstPhaseTotalSupply": 1, + "_firstPhaseMaxIssuance": 1, + "_minLockedPeriods": 2, + "_minAllowableLockedTokens": 0, + "_maxAllowableLockedTokens": deployer.economics.maximum_allowed_locked, + "_minWorkerPeriods": 1, + "_policyManager": policy_manager_mock.address, + "_adjudicator": adjudicator_mock.address + } + return parameters + + # Constructor parameters overrides for previous versions if needed # All versions below the specified version must use these overrides # 'None' value removes arg from list of constructor parameters CONSTRUCTOR_OVERRIDES = { - StakingEscrowDeployer.contract_name: {"v4.2.1": {"_issuanceDecayCoefficient": None, - "_lockDurationCoefficient1": None, - "_lockDurationCoefficient2": None, - "_maximumRewardedPeriods": None, - "_firstPhaseTotalSupply": None, - "_firstPhaseMaxIssuance": None, - "_miningCoefficient": 2, - "_lockedPeriodsCoefficient": 1, - "_rewardedPeriods": 1}, - "v5.7.1": {"_genesisHoursPerPeriod": None} - } + StakingEscrowDeployer.contract_name: { + "v5.7.1": lambda *args: {"_genesisHoursPerPeriod": None}, + "v6.1.1": parameters_v611 + } } FORCE_SKIP = { @@ -111,7 +140,10 @@ def deploy_base_contract(blockchain_interface: BlockchainDeployerInterface, overrides = dict() if len(raw_contracts[contract_name]) != 1: try: - overrides = CONSTRUCTOR_OVERRIDES[contract_name][latest_version] + overrides_func = CONSTRUCTOR_OVERRIDES[contract_name][latest_version] + overrides = overrides_func(blockchain_interface, + transacting_power, + deployer) except KeyError: pass @@ -135,19 +167,32 @@ def skip_test(blockchain_interface: BlockchainDeployerInterface, contract_name: return force_skip or len(raw_contracts[contract_name]) == 1 +def prepare_staker(blockchain_interface: TesterBlockchain, + deployer: StakingEscrowDeployer, + transacting_power: TransactingPower): + worklock_agent = WorkLockAgent(registry=deployer.registry) + value = worklock_agent.minimum_allowed_bid + worklock_agent.bid(value=value, transacting_power=transacting_power) + blockchain_interface.time_travel(hours=100) + worklock_agent.verify_bidding_correctness(transacting_power=transacting_power, gas_limit=1000000) + worklock_agent.claim(transacting_power=transacting_power) + + def test_upgradeability(temp_dir_path): # Prepare remote source for compilation download_github_dir(GITHUB_SOURCE_LINK, temp_dir_path) # Prepare the blockchain - BlockchainDeployerInterface.SOURCES = [ - SourceBundle(base_path=SOLIDITY_SOURCE_ROOT), + TesterBlockchain.SOURCES = [ + SourceBundle(base_path=SOLIDITY_SOURCE_ROOT, + other_paths=(TEST_SOLIDITY_SOURCE_ROOT,)), SourceBundle(base_path=Path(temp_dir_path)) ] provider_uri = 'tester://pyevm/2' # TODO: Testerchain caching Issues try: - blockchain_interface = BlockchainDeployerInterface(provider_uri=provider_uri, gas_strategy='free') + blockchain_interface = TesterBlockchain(gas_strategy='free') + blockchain_interface.provider_uri = provider_uri blockchain_interface.connect() origin = blockchain_interface.client.accounts[0] BlockchainInterfaceFactory.register_interface(interface=blockchain_interface) @@ -158,14 +203,10 @@ def test_upgradeability(temp_dir_path): economics = make_token_economics(blockchain_interface) # Check contracts with multiple versions - contract_name = AdjudicatorDeployer.contract_name - skip_adjudicator_test = skip_test(blockchain_interface, contract_name) contract_name = StakingEscrowDeployer.contract_name skip_staking_escrow_test = skip_test(blockchain_interface, contract_name) - contract_name = PolicyManagerDeployer.contract_name - skip_policy_manager_test = skip_test(blockchain_interface, contract_name) - if skip_adjudicator_test and skip_staking_escrow_test and skip_policy_manager_test: + if skip_staking_escrow_test: return # Prepare master version of contracts and upgrade to the latest @@ -177,17 +218,8 @@ def test_upgradeability(temp_dir_path): staking_escrow_deployer = StakingEscrowDeployer(registry=registry, economics=economics) staking_escrow_deployer.deploy(deployment_mode=constants.INIT, transacting_power=transacting_power) - policy_manager_deployer = PolicyManagerDeployer(registry=registry, economics=economics) - deploy_base_contract(blockchain_interface, policy_manager_deployer, - transacting_power=transacting_power, - skipt_test=skip_policy_manager_test) - - adjudicator_deployer = AdjudicatorDeployer(registry=registry, economics=economics) - deploy_base_contract(blockchain_interface, adjudicator_deployer, - transacting_power=transacting_power, - skipt_test=skip_adjudicator_test) - - if skip_staking_escrow_test: + if not skip_staking_escrow_test: + economics.worklock_supply = economics.maximum_allowed_locked worklock_deployer = WorklockDeployer(registry=registry, economics=economics) worklock_deployer.deploy(transacting_power=transacting_power) @@ -197,21 +229,13 @@ def test_upgradeability(temp_dir_path): skipt_test=skip_staking_escrow_test) if not skip_staking_escrow_test: - # TODO prepare at least one staker before calling upgrade + prepare_staker(blockchain_interface=blockchain_interface, + deployer=staking_escrow_deployer, + transacting_power=transacting_power) staking_escrow_deployer.upgrade(transacting_power=transacting_power, contract_version="latest", confirmations=0) - if not skip_policy_manager_test: - policy_manager_deployer.upgrade(transacting_power=transacting_power, - contract_version="latest", - confirmations=0) - - if not skip_adjudicator_test: - adjudicator_deployer.upgrade(transacting_power=transacting_power, - contract_version="latest", - confirmations=0) - finally: # Unregister interface # TODO: Move to method? with contextlib.suppress(KeyError):