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 # 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. # documentation root, use os.path.abspath to make it absolute, like shown here.
# #
import doctest
import os import os
import subprocess
import sys import sys
from pathlib import Path from pathlib import Path
@ -249,7 +248,6 @@ def run_apidoc(_):
"tests", "tests",
"scripts", "scripts",
Path("nucypher", "utilities"), Path("nucypher", "utilities"),
Path("nucypher", "blockchain", "economics.py"),
Path("nucypher", "cli"), Path("nucypher", "cli"),
] ]
for exclusion_item in exclusion_items: for exclusion_item in exclusion_items:
@ -271,8 +269,6 @@ autodoc_member_order = "bysource"
# -- Doctest configuration ---------------------------------------- # -- Doctest configuration ----------------------------------------
import doctest
doctest_default_flags = (0 doctest_default_flags = (0
| doctest.DONT_ACCEPT_TRUE_FOR_1 | doctest.DONT_ACCEPT_TRUE_FOR_1
| doctest.ELLIPSIS | 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 web3.types import TxReceipt
from nucypher.acumen.nicknames import Nickname from nucypher.acumen.nicknames import Nickname
from nucypher.blockchain.economics import Economics
from nucypher.blockchain.eth.agents import ( from nucypher.blockchain.eth.agents import (
AdjudicatorAgent, AdjudicatorAgent,
ContractAgency, ContractAgency,
@ -71,13 +70,13 @@ class BaseActor:
pass pass
@validate_checksum_address @validate_checksum_address
def __init__(self, def __init__(
domain: Optional[str], self,
registry: BaseContractRegistry, domain: Optional[str],
transacting_power: Optional[TransactingPower] = None, registry: BaseContractRegistry,
checksum_address: Optional[ChecksumAddress] = None, transacting_power: Optional[TransactingPower] = None,
economics: Optional[Economics] = None): checksum_address: Optional[ChecksumAddress] = None,
):
if not (bool(checksum_address) ^ bool(transacting_power)): if not (bool(checksum_address) ^ bool(transacting_power)):
error = f'Pass transacting power or checksum address, got {checksum_address} and {transacting_power}.' error = f'Pass transacting power or checksum address, got {checksum_address} and {transacting_power}.'
raise ValueError(error) raise ValueError(error)
@ -94,7 +93,6 @@ class BaseActor:
else: else:
self.checksum_address = checksum_address self.checksum_address = checksum_address
self.economics = economics or Economics()
self.transacting_power = transacting_power self.transacting_power = transacting_power
self.registry = registry self.registry = registry
self.network = domain self.network = domain

View File

@ -10,7 +10,6 @@ from cryptography.exceptions import InternalError
from eth_utils import to_checksum_address from eth_utils import to_checksum_address
from nucypher_core.umbral import PublicKey from nucypher_core.umbral import PublicKey
from nucypher.blockchain.economics import Economics
from nucypher.blockchain.eth.networks import NetworksInventory from nucypher.blockchain.eth.networks import NetworksInventory
from nucypher.blockchain.eth.token import TToken from nucypher.blockchain.eth.token import TToken
from nucypher.policy.payment import PRE_PAYMENT_METHODS 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? WEI = click.IntRange(min=1, clamp=False) # TODO: Better validation for ether and wei values?
GWEI = DecimalRange(min=0) 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) MIN_AUTHORIZATION = Decimal(__min_authorization)
STAKED_TOKENS_RANGE = DecimalRange(min=__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 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 # Get agents using same registry instance
application_agent_1 = ContractAgency.get_agent( application_agent_1 = ContractAgency.get_agent(
TACoApplicationAgent, TACoApplicationAgent,

View File

@ -4,14 +4,17 @@
import pytest import pytest
from eth_tester.exceptions import TransactionFailed 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.blockchain.eth.signers.software import Web3Signer
from nucypher.crypto.powers import TransactingPower from nucypher.crypto.powers import TransactingPower
from tests.constants import TEST_ETH_PROVIDER_URI
@pytest.fixture(scope='module') @pytest.fixture(scope='module')
def agent(testerchain, test_registry) -> NucypherTokenAgent: 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 return token_agent
@ -38,50 +41,54 @@ def test_token_properties(agent):
@pytest.mark.skip() @pytest.mark.skip()
def test_get_balance(agent, application_economics): def test_get_balance(agent):
testerchain = agent.blockchain testerchain = agent.blockchain
deployer, someone, *everybody_else = testerchain.client.accounts deployer, someone, *everybody_else = testerchain.client.accounts
balance = agent.get_balance(address=someone) balance = agent.get_balance(address=someone)
assert balance == 0 assert balance == 0
balance = agent.get_balance(address=deployer) balance = agent.get_balance(address=deployer)
assert balance == application_economics.erc20_total_supply assert balance > 0
@pytest.mark.skip() @pytest.mark.skip()
def test_approve_transfer(agent, application_economics): def test_approve_transfer(agent, taco_application_agent):
testerchain = agent.blockchain testerchain = agent.blockchain
deployer, someone, *everybody_else = testerchain.client.accounts deployer, someone, *everybody_else = testerchain.client.accounts
tpower = TransactingPower(account=someone, signer=Web3Signer(testerchain.client)) tpower = TransactingPower(account=someone, signer=Web3Signer(testerchain.client))
# Approve # Approve
receipt = agent.approve_transfer(amount=application_economics.min_authorization, receipt = agent.approve_transfer(
spender_address=agent.contract_address, amount=taco_application_agent.get_min_authorization(),
transacting_power=tpower) spender_address=agent.contract_address,
transacting_power=tpower,
)
assert receipt['status'] == 1, "Transaction Rejected" assert receipt['status'] == 1, "Transaction Rejected"
assert receipt['logs'][0]['address'] == agent.contract_address assert receipt['logs'][0]['address'] == agent.contract_address
@pytest.mark.skip() @pytest.mark.skip()
def test_transfer(agent, application_economics): def test_transfer(agent, taco_application_agent):
testerchain = agent.blockchain testerchain = agent.blockchain
origin, someone, *everybody_else = testerchain.client.accounts origin, someone, *everybody_else = testerchain.client.accounts
tpower = TransactingPower(account=origin, signer=Web3Signer(testerchain.client)) tpower = TransactingPower(account=origin, signer=Web3Signer(testerchain.client))
old_balance = agent.get_balance(someone) old_balance = agent.get_balance(someone)
receipt = agent.transfer(amount=application_economics.min_authorization, receipt = agent.transfer(
target_address=someone, amount=taco_application_agent.get_min_authorization(),
transacting_power=tpower) target_address=someone,
transacting_power=tpower,
)
assert receipt['status'] == 1, "Transaction Rejected" assert receipt['status'] == 1, "Transaction Rejected"
assert receipt['logs'][0]['address'] == agent.contract_address assert receipt['logs'][0]['address'] == agent.contract_address
new_balance = agent.get_balance(someone) 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() @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 testerchain = agent.blockchain
deployer, someone, *everybody_else = testerchain.client.accounts deployer, someone, *everybody_else = testerchain.client.accounts
@ -90,14 +97,19 @@ def test_approve_and_call(agent, application_economics, deploy_contract):
# Approve and call # Approve and call
tpower = TransactingPower(account=someone, signer=Web3Signer(testerchain.client)) tpower = TransactingPower(account=someone, signer=Web3Signer(testerchain.client))
call_data = b"Good morning, that's a nice tnetennba." call_data = b"Good morning, that's a nice tnetennba."
receipt = agent.approve_and_call(amount=application_economics.min_authorization, receipt = agent.approve_and_call(
target_address=mock_target.address, amount=taco_application_agent.get_min_authorization(),
transacting_power=tpower, target_address=mock_target.address,
call_data=call_data) transacting_power=tpower,
call_data=call_data,
)
assert receipt['status'] == 1, "Transaction Rejected" assert receipt['status'] == 1, "Transaction Rejected"
assert receipt['logs'][0]['address'] == agent.contract_address assert receipt['logs'][0]['address'] == agent.contract_address
assert mock_target.functions.extraData().call() == call_data assert mock_target.functions.extraData().call() == call_data
assert mock_target.functions.sender().call() == someone 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 from web3 import Web3
import tests import tests
from nucypher.blockchain.economics import Economics
from nucypher.blockchain.eth.actors import Operator from nucypher.blockchain.eth.actors import Operator
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
from nucypher.blockchain.eth.registry import LocalContractRegistry from nucypher.blockchain.eth.registry import LocalContractRegistry
@ -171,7 +170,7 @@ def bob_test_config(testerchain, test_registry):
@pytest.fixture(scope="module") @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""" """Creates a Policy, in a manner typical of how Alice might do it, with a unique label"""
random_label = generate_random_label() random_label = generate_random_label()
expiration = maya.now() + timedelta(days=1) 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') @pytest.fixture(scope='module')
def mock_testerchain() -> MockBlockchain: def mock_testerchain() -> MockBlockchain:
BlockchainInterfaceFactory._interfaces = dict() BlockchainInterfaceFactory._interfaces = dict()
@ -366,8 +359,10 @@ def policy_rate():
@pytest.fixture(scope='module') @pytest.fixture(scope='module')
def policy_value(application_economics, policy_rate): def policy_value(policy_rate):
value = policy_rate * application_economics.min_operator_seconds # TODO constant?
min_operator_seconds = 60 * 60 * 24 # one day in seconds
value = policy_rate * min_operator_seconds
return value return value

View File

@ -1,27 +1,13 @@
from decimal import Decimal, InvalidOperation
import pytest import pytest
from decimal import Decimal, InvalidOperation
from nucypher.blockchain.eth.token import NU from nucypher.blockchain.eth.token import NU
def test_NU(application_economics): def test_NU():
# 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'
# Alternate construction # Alternate construction
assert NU(1, 'NU') == NU('1.0', 'NU') == NU(1.0, 'NU') 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) @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 mock_contract_agency._MockContractAgency__agents[CoordinatorAgent] = COORDINATOR
yield COORDINATOR yield COORDINATOR

View File

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

View File

@ -1,7 +1,6 @@
import pytest import pytest
from nucypher_core.ferveo import Keypair, Validator from nucypher_core.ferveo import Keypair, Validator
from nucypher.blockchain.economics import EconomicsFactory
from nucypher.blockchain.eth.actors import Operator from nucypher.blockchain.eth.actors import Operator
from nucypher.blockchain.eth.agents import ContractAgency from nucypher.blockchain.eth.agents import ContractAgency
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
@ -34,11 +33,7 @@ def mock_transacting_power(module_mocker):
@pytest.fixture(scope='module', autouse=True) @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 from tests.mock.agents import MockContractAgency
# Monkeypatch # TODO: Use better tooling for this monkeypatch? # 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 hexbytes import HexBytes
from web3 import Web3 from web3 import Web3
from nucypher.blockchain.economics import Economics
from nucypher.blockchain.eth.interfaces import ( from nucypher.blockchain.eth.interfaces import (
BlockchainInterface, BlockchainInterface,
) )
@ -74,9 +73,6 @@ class TesterBlockchain(BlockchainInterface):
__OPERATORS_RANGE = range(NUMBER_OF_URSULAS_IN_BLOCKCHAIN_TESTS) __OPERATORS_RANGE = range(NUMBER_OF_URSULAS_IN_BLOCKCHAIN_TESTS)
__ACCOUNT_CACHE = list() __ACCOUNT_CACHE = list()
# Defaults
DEFAULT_ECONOMICS = Economics()
def __init__(self, def __init__(self,
test_accounts: int = NUMBER_OF_ETH_TEST_ACCOUNTS, test_accounts: int = NUMBER_OF_ETH_TEST_ACCOUNTS,
poa: bool = True, poa: bool = True,