Remove EconomicsFactory/Economics.

pull/3241/head
derekpierre 2023-09-21 11:07:20 -04:00
parent 2ed9423c57
commit 869ef1fbda
13 changed files with 53 additions and 209 deletions

View File

@ -29,9 +29,8 @@
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import doctest
import os
import subprocess
import sys
from pathlib import Path
@ -249,7 +248,6 @@ def run_apidoc(_):
"tests",
"scripts",
Path("nucypher", "utilities"),
Path("nucypher", "blockchain", "economics.py"),
Path("nucypher", "cli"),
]
for exclusion_item in exclusion_items:
@ -271,8 +269,6 @@ autodoc_member_order = "bysource"
# -- Doctest configuration ----------------------------------------
import doctest
doctest_default_flags = (0
| doctest.DONT_ACCEPT_TRUE_FOR_1
| doctest.ELLIPSIS

View File

@ -1,119 +0,0 @@
from typing import Optional, Tuple
from web3 import Web3
from web3.types import Wei
from nucypher.blockchain.eth.agents import ContractAgency, TACoApplicationAgent
from nucypher.blockchain.eth.registry import BaseContractRegistry
from nucypher.blockchain.eth.token import TToken
class Economics:
_default_min_authorization = TToken(40_000, 'T').to_units()
_default_min_operator_seconds = 60 * 60 * 24 # one day in seconds
_default_fee_rate = Wei(Web3.to_wei(1, 'gwei'))
# TODO: Reintroduce Adjudicator
# Slashing parameters
# HASH_ALGORITHM_KECCAK256 = 0
# HASH_ALGORITHM_SHA256 = 1
# HASH_ALGORITHM_RIPEMD160 = 2
# _default_hash_algorithm = HASH_ALGORITHM_SHA256
# _default_base_penalty = 2
# _default_penalty_history_coefficient = 0
# _default_percentage_penalty_coefficient = 100000 # 0.001%
# _default_reward_coefficient = 2
def __init__(self,
min_operator_seconds: int = _default_min_operator_seconds,
min_authorization: int = _default_min_authorization,
fee_rate: Wei = _default_fee_rate,
# Adjudicator
# hash_algorithm: int = _default_hash_algorithm,
# base_penalty: int = _default_base_penalty,
# penalty_history_coefficient: int = _default_penalty_history_coefficient,
# percentage_penalty_coefficient: int = _default_percentage_penalty_coefficient,
# reward_coefficient: int = _default_reward_coefficient
):
"""
:param min_operator_seconds: Min amount of seconds while an operator can't be changed
:param min_authorization: Amount of minimum allowable authorization
"""
# TODO: Reintroduce Adjudicator
# :param hash_algorithm: Hashing algorithm
# :param base_penalty: Base for the penalty calculation
# :param penalty_history_coefficient: Coefficient for calculating the penalty depending on the history
# :param percentage_penalty_coefficient: Coefficient for calculating the percentage penalty
# :param reward_coefficient: Coefficient for calculating the reward
# self.hash_algorithm = hash_algorithm
# self.base_penalty = base_penalty
# self.penalty_history_coefficient = penalty_history_coefficient
# self.percentage_penalty_coefficient = percentage_penalty_coefficient
# self.reward_coefficient = reward_coefficient
self.min_operator_seconds = min_operator_seconds
self.min_authorization = min_authorization
self.fee_rate = fee_rate
@property
def taco_application_deployment_parameters(self) -> Tuple[int, ...]:
"""Cast coefficient attributes to uint256 compatible type for solidity+EVM"""
deploy_parameters = ( # note: order-sensitive
self.min_authorization,
self.min_operator_seconds,
)
return tuple(map(int, deploy_parameters))
# TODO: Reintroduce Adjudicator
# @property
# def slashing_deployment_parameters(self) -> Tuple[int, ...]:
# """Cast coefficient attributes to uint256 compatible type for solidity+EVM"""
# deployment_parameters = [
# self.hash_algorithm,
# self.base_penalty,
# self.penalty_history_coefficient,
# self.percentage_penalty_coefficient,
# self.reward_coefficient
# ]
# return tuple(map(int, deployment_parameters))
class EconomicsFactory:
# TODO: Enforce singleton
__economics = dict()
@classmethod
def get_economics(cls, registry: BaseContractRegistry, eth_provider_uri: Optional[str] = None) -> Economics:
registry_id = registry.id
try:
return cls.__economics[registry_id]
except KeyError:
economics = EconomicsFactory.retrieve_from_blockchain(registry=registry, eth_provider_uri=eth_provider_uri)
cls.__economics[registry_id] = economics
return economics
@staticmethod
def retrieve_from_blockchain(registry: BaseContractRegistry, eth_provider_uri: Optional[str] = None) -> Economics:
# Agents
application_agent = ContractAgency.get_agent(
TACoApplicationAgent, registry=registry, provider_uri=eth_provider_uri
)
# TACo Application
min_authorization = application_agent.get_min_authorization()
min_operator_seconds = application_agent.get_min_operator_seconds()
# Aggregate
economics_parameters = dict(min_authorization=min_authorization,
min_operator_seconds=min_operator_seconds)
economics = Economics(**economics_parameters)
return economics

View File

@ -27,7 +27,6 @@ from web3 import HTTPProvider, Web3
from web3.types import TxReceipt
from nucypher.acumen.nicknames import Nickname
from nucypher.blockchain.economics import Economics
from nucypher.blockchain.eth.agents import (
AdjudicatorAgent,
ContractAgency,
@ -71,13 +70,13 @@ class BaseActor:
pass
@validate_checksum_address
def __init__(self,
domain: Optional[str],
registry: BaseContractRegistry,
transacting_power: Optional[TransactingPower] = None,
checksum_address: Optional[ChecksumAddress] = None,
economics: Optional[Economics] = None):
def __init__(
self,
domain: Optional[str],
registry: BaseContractRegistry,
transacting_power: Optional[TransactingPower] = None,
checksum_address: Optional[ChecksumAddress] = None,
):
if not (bool(checksum_address) ^ bool(transacting_power)):
error = f'Pass transacting power or checksum address, got {checksum_address} and {transacting_power}.'
raise ValueError(error)
@ -94,7 +93,6 @@ class BaseActor:
else:
self.checksum_address = checksum_address
self.economics = economics or Economics()
self.transacting_power = transacting_power
self.registry = registry
self.network = domain

View File

@ -10,7 +10,6 @@ from cryptography.exceptions import InternalError
from eth_utils import to_checksum_address
from nucypher_core.umbral import PublicKey
from nucypher.blockchain.economics import Economics
from nucypher.blockchain.eth.networks import NetworksInventory
from nucypher.blockchain.eth.token import TToken
from nucypher.policy.payment import PRE_PAYMENT_METHODS
@ -128,7 +127,8 @@ EIP55_CHECKSUM_ADDRESS = ChecksumAddress()
WEI = click.IntRange(min=1, clamp=False) # TODO: Better validation for ether and wei values?
GWEI = DecimalRange(min=0)
__min_authorization = TToken.from_units(Economics._default_min_authorization).to_tokens()
__min_authorization = TToken(40_000, "T").to_tokens() # TODO right spot for this?
MIN_AUTHORIZATION = Decimal(__min_authorization)
STAKED_TOKENS_RANGE = DecimalRange(min=__min_authorization)

View File

@ -4,7 +4,7 @@ from nucypher.blockchain.eth.agents import ContractAgency, TACoApplicationAgent
from tests.constants import TEST_ETH_PROVIDER_URI
def test_get_agent_with_different_registries(application_economics, test_registry, agency_local_registry):
def test_get_agent_with_different_registries(test_registry, agency_local_registry):
# Get agents using same registry instance
application_agent_1 = ContractAgency.get_agent(
TACoApplicationAgent,

View File

@ -4,14 +4,17 @@
import pytest
from eth_tester.exceptions import TransactionFailed
from nucypher.blockchain.eth.agents import NucypherTokenAgent, ContractAgency
from nucypher.blockchain.eth.agents import ContractAgency, NucypherTokenAgent
from nucypher.blockchain.eth.signers.software import Web3Signer
from nucypher.crypto.powers import TransactingPower
from tests.constants import TEST_ETH_PROVIDER_URI
@pytest.fixture(scope='module')
def agent(testerchain, test_registry) -> NucypherTokenAgent:
token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=test_registry)
token_agent = ContractAgency.get_agent(
NucypherTokenAgent, registry=test_registry, provider_uri=TEST_ETH_PROVIDER_URI
)
return token_agent
@ -38,50 +41,54 @@ def test_token_properties(agent):
@pytest.mark.skip()
def test_get_balance(agent, application_economics):
def test_get_balance(agent):
testerchain = agent.blockchain
deployer, someone, *everybody_else = testerchain.client.accounts
balance = agent.get_balance(address=someone)
assert balance == 0
balance = agent.get_balance(address=deployer)
assert balance == application_economics.erc20_total_supply
assert balance > 0
@pytest.mark.skip()
def test_approve_transfer(agent, application_economics):
def test_approve_transfer(agent, taco_application_agent):
testerchain = agent.blockchain
deployer, someone, *everybody_else = testerchain.client.accounts
tpower = TransactingPower(account=someone, signer=Web3Signer(testerchain.client))
# Approve
receipt = agent.approve_transfer(amount=application_economics.min_authorization,
spender_address=agent.contract_address,
transacting_power=tpower)
receipt = agent.approve_transfer(
amount=taco_application_agent.get_min_authorization(),
spender_address=agent.contract_address,
transacting_power=tpower,
)
assert receipt['status'] == 1, "Transaction Rejected"
assert receipt['logs'][0]['address'] == agent.contract_address
@pytest.mark.skip()
def test_transfer(agent, application_economics):
def test_transfer(agent, taco_application_agent):
testerchain = agent.blockchain
origin, someone, *everybody_else = testerchain.client.accounts
tpower = TransactingPower(account=origin, signer=Web3Signer(testerchain.client))
old_balance = agent.get_balance(someone)
receipt = agent.transfer(amount=application_economics.min_authorization,
target_address=someone,
transacting_power=tpower)
receipt = agent.transfer(
amount=taco_application_agent.get_min_authorization(),
target_address=someone,
transacting_power=tpower,
)
assert receipt['status'] == 1, "Transaction Rejected"
assert receipt['logs'][0]['address'] == agent.contract_address
new_balance = agent.get_balance(someone)
assert new_balance == old_balance + application_economics.min_authorization
assert new_balance == old_balance + taco_application_agent.get_min_authorization()
@pytest.mark.skip()
def test_approve_and_call(agent, application_economics, deploy_contract):
def test_approve_and_call(agent, taco_application_agent, deploy_contract):
testerchain = agent.blockchain
deployer, someone, *everybody_else = testerchain.client.accounts
@ -90,14 +97,19 @@ def test_approve_and_call(agent, application_economics, deploy_contract):
# Approve and call
tpower = TransactingPower(account=someone, signer=Web3Signer(testerchain.client))
call_data = b"Good morning, that's a nice tnetennba."
receipt = agent.approve_and_call(amount=application_economics.min_authorization,
target_address=mock_target.address,
transacting_power=tpower,
call_data=call_data)
receipt = agent.approve_and_call(
amount=taco_application_agent.get_min_authorization(),
target_address=mock_target.address,
transacting_power=tpower,
call_data=call_data,
)
assert receipt['status'] == 1, "Transaction Rejected"
assert receipt['logs'][0]['address'] == agent.contract_address
assert mock_target.functions.extraData().call() == call_data
assert mock_target.functions.sender().call() == someone
assert mock_target.functions.value().call() == application_economics.min_authorization
assert (
mock_target.functions.value().call()
== taco_application_agent.get_min_authorization()
)

View File

@ -18,7 +18,6 @@ from twisted.internet.task import Clock
from web3 import Web3
import tests
from nucypher.blockchain.economics import Economics
from nucypher.blockchain.eth.actors import Operator
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
from nucypher.blockchain.eth.registry import LocalContractRegistry
@ -171,7 +170,7 @@ def bob_test_config(testerchain, test_registry):
@pytest.fixture(scope="module")
def idle_policy(testerchain, alice, bob, application_economics):
def idle_policy(testerchain, alice, bob):
"""Creates a Policy, in a manner typical of how Alice might do it, with a unique label"""
random_label = generate_random_label()
expiration = maya.now() + timedelta(days=1)
@ -304,12 +303,6 @@ def lonely_ursula_maker(ursula_test_config, testerchain):
#
@pytest.fixture(scope='module')
def application_economics():
economics = Economics()
return economics
@pytest.fixture(scope='module')
def mock_testerchain() -> MockBlockchain:
BlockchainInterfaceFactory._interfaces = dict()
@ -366,8 +359,10 @@ def policy_rate():
@pytest.fixture(scope='module')
def policy_value(application_economics, policy_rate):
value = policy_rate * application_economics.min_operator_seconds
def policy_value(policy_rate):
# TODO constant?
min_operator_seconds = 60 * 60 * 24 # one day in seconds
value = policy_rate * min_operator_seconds
return value

View File

@ -1,27 +1,13 @@
from decimal import Decimal, InvalidOperation
import pytest
from decimal import Decimal, InvalidOperation
from nucypher.blockchain.eth.token import NU
def test_NU(application_economics):
# Starting Small
min_allowed_locked = NU(application_economics.min_authorization, 'NuNit')
assert application_economics.min_authorization == int(min_allowed_locked.to_units())
min_NU_locked = int(str(application_economics.min_authorization)[0:-18])
expected = NU(min_NU_locked, 'NU')
assert min_allowed_locked == expected
# TODO: Use minimums for T staking
# Starting Big
# min_allowed_locked = NU(min_NU_locked, 'NU')
# assert token_economics.min_authorization == int(min_allowed_locked)
# assert token_economics.min_authorization == int(min_allowed_locked.to_units())
# assert str(min_allowed_locked) == '40000 NU'
def test_NU():
# Alternate construction
assert NU(1, 'NU') == NU('1.0', 'NU') == NU(1.0, 'NU')

View File

@ -1,12 +0,0 @@
import pytest
from nucypher.blockchain.economics import EconomicsFactory
@pytest.mark.usefixtures('testerchain')
def test_retrieving_from_blockchain(application_economics, test_registry):
economics = EconomicsFactory.get_economics(registry=test_registry)
assert (
economics.taco_application_deployment_parameters
== application_economics.taco_application_deployment_parameters
)

View File

@ -53,7 +53,7 @@ COORDINATOR = MockCoordinatorAgent(MockBlockchain())
@pytest.fixture(scope="function", autouse=True)
def mock_coordinator_agent(testerchain, application_economics, mock_contract_agency):
def mock_coordinator_agent(testerchain, mock_contract_agency):
mock_contract_agency._MockContractAgency__agents[CoordinatorAgent] = COORDINATOR
yield COORDINATOR

View File

@ -5,7 +5,6 @@ from typing import Iterable, Optional
import pytest
from eth_account.account import Account
from nucypher.blockchain.economics import EconomicsFactory
from nucypher.blockchain.eth.actors import Operator
from nucypher.blockchain.eth.agents import (
AdjudicatorAgent,
@ -149,10 +148,8 @@ def test_registry_source_manager(testerchain, test_registry):
@pytest.fixture(scope='module', autouse=True)
def mock_contract_agency(module_mocker, application_economics):
def mock_contract_agency():
# Patch
module_mocker.patch.object(EconomicsFactory, 'get_economics', return_value=application_economics)
from tests.mock.agents import MockContractAgency
# Monkeypatch # TODO: Use better tooling for this monkeypatch?

View File

@ -1,7 +1,6 @@
import pytest
from nucypher_core.ferveo import Keypair, Validator
from nucypher.blockchain.economics import EconomicsFactory
from nucypher.blockchain.eth.actors import Operator
from nucypher.blockchain.eth.agents import ContractAgency
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
@ -34,11 +33,7 @@ def mock_transacting_power(module_mocker):
@pytest.fixture(scope='module', autouse=True)
def mock_contract_agency(module_mocker, application_economics):
# Patch
module_mocker.patch.object(EconomicsFactory, 'get_economics', return_value=application_economics)
def mock_contract_agency():
from tests.mock.agents import MockContractAgency
# Monkeypatch # TODO: Use better tooling for this monkeypatch?

View File

@ -6,7 +6,6 @@ from eth_tester.exceptions import TransactionFailed
from hexbytes import HexBytes
from web3 import Web3
from nucypher.blockchain.economics import Economics
from nucypher.blockchain.eth.interfaces import (
BlockchainInterface,
)
@ -74,9 +73,6 @@ class TesterBlockchain(BlockchainInterface):
__OPERATORS_RANGE = range(NUMBER_OF_URSULAS_IN_BLOCKCHAIN_TESTS)
__ACCOUNT_CACHE = list()
# Defaults
DEFAULT_ECONOMICS = Economics()
def __init__(self,
test_accounts: int = NUMBER_OF_ETH_TEST_ACCOUNTS,
poa: bool = True,