mirror of https://github.com/nucypher/nucypher.git
446 lines
12 KiB
Python
446 lines
12 KiB
Python
import random
|
|
|
|
import maya
|
|
import pytest
|
|
from web3 import Web3
|
|
|
|
import tests
|
|
from nucypher.blockchain.eth.actors import Operator
|
|
from nucypher.blockchain.eth.agents import (
|
|
ContractAgency,
|
|
CoordinatorAgent,
|
|
TACoApplicationAgent,
|
|
TACoChildApplicationAgent,
|
|
)
|
|
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
|
|
from nucypher.blockchain.eth.registry import ContractRegistry, RegistrySourceManager
|
|
from nucypher.utilities.logging import Logger
|
|
from tests.constants import (
|
|
BONUS_TOKENS_FOR_TESTS,
|
|
MIN_OPERATOR_SECONDS,
|
|
TEMPORARY_DOMAIN,
|
|
TEST_ETH_PROVIDER_URI,
|
|
)
|
|
from tests.utils.blockchain import ReservedTestAccountManager, TesterBlockchain
|
|
from tests.utils.registry import ApeRegistrySource
|
|
from tests.utils.ursula import (
|
|
mock_permitted_multichain_connections,
|
|
setup_multichain_ursulas,
|
|
)
|
|
|
|
test_logger = Logger("acceptance-test-logger")
|
|
|
|
ONE_DAY = 24 * 60 * 60
|
|
|
|
# ERC-20
|
|
TOTAL_SUPPLY = Web3.to_wei(11_000_000_000, "ether")
|
|
NU_TOTAL_SUPPLY = Web3.to_wei(
|
|
1_000_000_000, "ether"
|
|
) # TODO NU(1_000_000_000, 'NU').to_units()
|
|
|
|
# TACo Application
|
|
MIN_AUTHORIZATION = Web3.to_wei(40_000, "ether")
|
|
|
|
REWARD_DURATION = 7 * ONE_DAY # one week in seconds
|
|
DEAUTHORIZATION_DURATION = 60 * ONE_DAY # 60 days in seconds
|
|
|
|
COMMITMENT_DURATION_1 = 182 * ONE_DAY # 182 days in seconds
|
|
COMMITMENT_DURATION_2 = 2 * COMMITMENT_DURATION_1 # 365 days in seconds
|
|
|
|
COMMITMENT_DEADLINE = 100 * ONE_DAY # 100 days after deployment
|
|
|
|
PENALTY_DEFAULT = 1000 # 10% penalty
|
|
PENALTY_INCREMENT = 2500 # 25% penalty increment
|
|
PENALTY_DURATION = ONE_DAY # 1 day in seconds
|
|
|
|
|
|
# Coordinator
|
|
TIMEOUT = 3600
|
|
MAX_DKG_SIZE = 8
|
|
FEE_RATE = 1
|
|
|
|
|
|
#
|
|
# General
|
|
#
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def monkeymodule():
|
|
from _pytest.monkeypatch import MonkeyPatch
|
|
|
|
mpatch = MonkeyPatch()
|
|
yield mpatch
|
|
mpatch.undo()
|
|
|
|
|
|
#
|
|
# Accounts
|
|
#
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def accounts():
|
|
return ReservedTestAccountManager()
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def deployer_account(accounts):
|
|
return accounts[0]
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def initiator(testerchain, alice, ritual_token, deployer_account):
|
|
"""Returns the Initiator, funded with RitualToken"""
|
|
# transfer ritual token to alice (initiator)
|
|
ritual_token.transfer(
|
|
alice.transacting_power.account,
|
|
Web3.to_wei(1, "ether"),
|
|
sender=deployer_account,
|
|
)
|
|
return alice
|
|
|
|
|
|
#
|
|
# Contracts Dependencies
|
|
#
|
|
|
|
|
|
@pytest.fixture(scope="session", autouse=True)
|
|
def nucypher_dependency(project):
|
|
nucypher_contracts_dependency_api = project.dependencies["nucypher-contracts"]
|
|
# simply use first entry - could be from github ('main') or local ('local')
|
|
_, nucypher_dependency = list(nucypher_contracts_dependency_api.items())[0]
|
|
return nucypher_dependency
|
|
|
|
|
|
@pytest.fixture(scope="session", autouse=True)
|
|
def oz_dependency(project):
|
|
_oz_dependency = project.dependencies["openzeppelin"]["5.0.0"]
|
|
return _oz_dependency
|
|
|
|
|
|
#
|
|
# Contracts
|
|
#
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def ritual_token(project, deployer_account):
|
|
_ritual_token = deployer_account.deploy(project.RitualToken, TOTAL_SUPPLY)
|
|
return _ritual_token
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def t_token(nucypher_dependency, deployer_account):
|
|
_t_token = deployer_account.deploy(nucypher_dependency.TestToken, TOTAL_SUPPLY)
|
|
return _t_token
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def threshold_staking(nucypher_dependency, deployer_account):
|
|
_threshold_staking = deployer_account.deploy(
|
|
nucypher_dependency.TestnetThresholdStaking
|
|
)
|
|
return _threshold_staking
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def taco_application(
|
|
oz_dependency,
|
|
nucypher_dependency,
|
|
deployer_account,
|
|
t_token,
|
|
threshold_staking,
|
|
):
|
|
taco_application_implementation = deployer_account.deploy(
|
|
nucypher_dependency.TACoApplication,
|
|
t_token.address,
|
|
threshold_staking.address,
|
|
MIN_AUTHORIZATION,
|
|
MIN_OPERATOR_SECONDS,
|
|
REWARD_DURATION,
|
|
DEAUTHORIZATION_DURATION,
|
|
[COMMITMENT_DURATION_1, COMMITMENT_DURATION_2],
|
|
maya.now().epoch + COMMITMENT_DEADLINE,
|
|
PENALTY_DEFAULT,
|
|
PENALTY_DURATION,
|
|
PENALTY_INCREMENT,
|
|
)
|
|
|
|
proxy = deployer_account.deploy(
|
|
oz_dependency.TransparentUpgradeableProxy,
|
|
taco_application_implementation.address,
|
|
deployer_account.address,
|
|
b"",
|
|
)
|
|
proxy_contract = nucypher_dependency.TACoApplication.at(proxy.address)
|
|
|
|
threshold_staking.setApplication(proxy_contract.address, sender=deployer_account)
|
|
proxy_contract.initialize(sender=deployer_account)
|
|
|
|
return proxy_contract
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def taco_child_application(
|
|
oz_dependency,
|
|
nucypher_dependency,
|
|
deployer_account,
|
|
taco_application,
|
|
):
|
|
taco_child_application_implementation = deployer_account.deploy(
|
|
nucypher_dependency.TACoChildApplication,
|
|
taco_application.address,
|
|
MIN_AUTHORIZATION,
|
|
)
|
|
|
|
proxy = deployer_account.deploy(
|
|
oz_dependency.TransparentUpgradeableProxy,
|
|
taco_child_application_implementation.address,
|
|
deployer_account.address,
|
|
b"",
|
|
)
|
|
proxy_contract = nucypher_dependency.TACoChildApplication.at(proxy.address)
|
|
taco_application.setChildApplication(
|
|
proxy_contract.address, sender=deployer_account
|
|
)
|
|
|
|
return proxy_contract
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def adjudicator(module_mocker, get_random_checksum_address):
|
|
_adjudicator = module_mocker.Mock()
|
|
_adjudicator.address = get_random_checksum_address()
|
|
return _adjudicator
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def coordinator(
|
|
oz_dependency,
|
|
nucypher_dependency,
|
|
deployer_account,
|
|
taco_child_application,
|
|
ritual_token,
|
|
adjudicator,
|
|
):
|
|
_coordinator = deployer_account.deploy(
|
|
nucypher_dependency.Coordinator,
|
|
taco_child_application.address,
|
|
)
|
|
|
|
encoded_initializer_function = _coordinator.initialize.encode_input(
|
|
TIMEOUT, MAX_DKG_SIZE, deployer_account.address
|
|
)
|
|
proxy = deployer_account.deploy(
|
|
oz_dependency.TransparentUpgradeableProxy,
|
|
_coordinator.address,
|
|
deployer_account.address,
|
|
encoded_initializer_function,
|
|
)
|
|
|
|
proxy_contract = nucypher_dependency.Coordinator.at(proxy.address)
|
|
taco_child_application.initialize(
|
|
proxy_contract.address, adjudicator.address, sender=deployer_account
|
|
)
|
|
return proxy_contract
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def fee_model(nucypher_dependency, deployer_account, coordinator, ritual_token):
|
|
contract = deployer_account.deploy(
|
|
nucypher_dependency.FlatRateFeeModel,
|
|
coordinator.address,
|
|
ritual_token.address,
|
|
FEE_RATE,
|
|
)
|
|
treasury_role = coordinator.TREASURY_ROLE()
|
|
coordinator.grantRole(
|
|
treasury_role, deployer_account.address, sender=deployer_account
|
|
)
|
|
coordinator.approveFeeModel(contract.address, sender=deployer_account)
|
|
|
|
return contract
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def global_allow_list(nucypher_dependency, deployer_account, coordinator):
|
|
contract = deployer_account.deploy(
|
|
nucypher_dependency.GlobalAllowList,
|
|
coordinator.address,
|
|
)
|
|
|
|
return contract
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def subscription_manager(nucypher_dependency, deployer_account):
|
|
_subscription_manager = deployer_account.deploy(
|
|
nucypher_dependency.SubscriptionManager,
|
|
)
|
|
return _subscription_manager
|
|
|
|
#
|
|
# Deployment/Blockchains
|
|
#
|
|
|
|
|
|
@pytest.fixture(scope="module", autouse=True)
|
|
def deployed_contracts(
|
|
ritual_token,
|
|
t_token,
|
|
threshold_staking,
|
|
taco_application,
|
|
taco_child_application,
|
|
coordinator,
|
|
fee_model,
|
|
global_allow_list,
|
|
subscription_manager,
|
|
):
|
|
# TODO: can this be improved - eg. get it from the project fixture
|
|
deployments = [
|
|
ritual_token,
|
|
t_token,
|
|
threshold_staking,
|
|
taco_application,
|
|
taco_child_application,
|
|
coordinator,
|
|
fee_model,
|
|
global_allow_list,
|
|
subscription_manager,
|
|
]
|
|
ApeRegistrySource.set_deployments(deployments)
|
|
return deployments
|
|
|
|
|
|
@pytest.fixture(scope="module", autouse=True)
|
|
def test_registry(deployed_contracts, module_mocker):
|
|
with tests.utils.registry.mock_registry_sources(mocker=module_mocker):
|
|
RegistrySourceManager._FALLBACK_CHAIN = (ApeRegistrySource,)
|
|
source = ApeRegistrySource(domain=TEMPORARY_DOMAIN)
|
|
registry = ContractRegistry(source=source)
|
|
yield registry
|
|
|
|
|
|
@pytest.mark.usefixtures("test_registry")
|
|
@pytest.fixture(scope="module")
|
|
def testerchain(project, clock, accounts) -> TesterBlockchain:
|
|
# Extract the web3 provider containing EthereumTester from the ape project's chain manager
|
|
provider = project.chain_manager.provider.web3.provider
|
|
testerchain = TesterBlockchain(provider=provider)
|
|
testerchain.tx_machine._task.clock = clock
|
|
BlockchainInterfaceFactory.register_interface(interface=testerchain, force=True)
|
|
yield testerchain
|
|
|
|
|
|
#
|
|
# Staking
|
|
#
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def staking_providers(
|
|
deployer_account,
|
|
accounts,
|
|
testerchain,
|
|
threshold_staking,
|
|
taco_application,
|
|
):
|
|
minimum_stake = taco_application.minimumAuthorization()
|
|
|
|
staking_providers = list()
|
|
for provider_address, operator_address in zip(
|
|
accounts.staking_providers_accounts, accounts.ursulas_accounts
|
|
):
|
|
# for a random amount
|
|
amount = minimum_stake + random.randrange(BONUS_TOKENS_FOR_TESTS)
|
|
|
|
# initialize threshold stake via threshold staking (permission-less mock)
|
|
threshold_staking.setRoles(provider_address, sender=deployer_account)
|
|
|
|
threshold_staking.authorizationIncreased(
|
|
provider_address, 0, amount, sender=deployer_account
|
|
)
|
|
|
|
taco_application.bondOperator(
|
|
provider_address,
|
|
operator_address,
|
|
sender=accounts[provider_address],
|
|
)
|
|
|
|
# track
|
|
staking_providers.append(provider_address)
|
|
|
|
yield staking_providers
|
|
|
|
|
|
#
|
|
# Agents
|
|
#
|
|
|
|
|
|
@pytest.fixture(scope="module", autouse=True)
|
|
def coordinator_agent(testerchain, test_registry):
|
|
"""Creates a coordinator agent"""
|
|
coordinator = ContractAgency.get_agent(
|
|
CoordinatorAgent,
|
|
registry=test_registry,
|
|
blockchain_endpoint=TEST_ETH_PROVIDER_URI,
|
|
)
|
|
return coordinator
|
|
|
|
|
|
@pytest.fixture(scope="module", autouse=True)
|
|
def taco_application_agent(test_registry):
|
|
_taco_application_agent = ContractAgency.get_agent(
|
|
TACoApplicationAgent,
|
|
registry=test_registry,
|
|
blockchain_endpoint=TEST_ETH_PROVIDER_URI,
|
|
)
|
|
|
|
return _taco_application_agent
|
|
|
|
|
|
@pytest.fixture(scope="module", autouse=True)
|
|
def taco_child_application_agent(testerchain, test_registry):
|
|
_taco_child_application_agent = ContractAgency.get_agent(
|
|
TACoChildApplicationAgent,
|
|
registry=test_registry,
|
|
blockchain_endpoint=TEST_ETH_PROVIDER_URI,
|
|
)
|
|
|
|
return _taco_child_application_agent
|
|
|
|
|
|
#
|
|
# Conditions
|
|
#
|
|
|
|
@pytest.fixture(scope="module")
|
|
def multichain_ids(module_mocker):
|
|
ids = mock_permitted_multichain_connections(mocker=module_mocker)
|
|
return ids
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def multichain_ursulas(ursulas, multichain_ids):
|
|
setup_multichain_ursulas(ursulas=ursulas, chain_ids=multichain_ids)
|
|
return ursulas
|
|
|
|
|
|
@pytest.fixture(scope="module", autouse=True)
|
|
def mock_condition_blockchains(module_mocker):
|
|
"""adds testerchain's chain ID to permitted conditional chains"""
|
|
|
|
module_mocker.patch(
|
|
"nucypher.blockchain.eth.domains.get_domain", return_value=TEMPORARY_DOMAIN
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope="module", autouse=True)
|
|
def mock_multichain_configuration(module_mocker, testerchain):
|
|
module_mocker.patch.object(
|
|
Operator, "_make_condition_provider", return_value=testerchain.provider
|
|
)
|