Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed calculation of deposit_amount #249

Merged
merged 6 commits into from
Aug 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions scenario_player/exceptions/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ class ConfigurationError(ValueError):
"""Generic error thrown if there was an error while reading the scenario file."""


class UDCTokenConfigError(ConfigurationError):
"""Invalid Configuration parameters. Most likely there is an issue with Token amounts"""


class InsufficientMintingAmount(ConfigurationError):
"""The minted amount set in token.min_balance is not sufficient"""


class NodeConfigurationError(ConfigurationError):
"""An error occurred while validating the nodes setting of a scenario file."""

Expand Down
15 changes: 15 additions & 0 deletions scenario_player/scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import yaml

from scenario_player.constants import GAS_LIMIT_FOR_TOKEN_CONTRACT_CALL
from scenario_player.exceptions.config import InsufficientMintingAmount
from scenario_player.utils.configuration import (
NodesConfig,
ScenarioConfig,
Expand Down Expand Up @@ -33,10 +34,24 @@ def __init__(self, yaml_path: pathlib.Path, data_path: pathlib.Path) -> None:
self.scenario = ScenarioConfig(self._loaded)
self.token = TokenConfig(self._loaded, data_path.joinpath("token.info"))
self.spaas = SPaaSConfig(self._loaded)
self.validate()

self.gas_limit = GAS_LIMIT_FOR_TOKEN_CONTRACT_CALL * 2

@property
def name(self) -> str:
"""Return the name of the scenario file, sans extension."""
return self.path.stem

def validate(self):
"""Validate cross-config section requirements of the scenario.

:raises InsufficientMintingAmount:
If token.min_balance < settings.services.udc.token.max_funding
"""

# Check that the amount of minted tokens is >= than the amount of deposited tokens
try:
assert self.token.min_balance >= self.settings.services.udc.token.max_funding
except AssertionError:
raise InsufficientMintingAmount
10 changes: 9 additions & 1 deletion scenario_player/utils/configuration/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import structlog

from scenario_player.constants import GAS_STRATEGIES, TIMEOUT
from scenario_player.exceptions.config import ScenarioConfigurationError, ServiceConfigurationError
from scenario_player.exceptions.config import (
ScenarioConfigurationError,
ServiceConfigurationError,
UDCTokenConfigError,
)
from scenario_player.utils.configuration.base import ConfigMapping

log = structlog.get_logger(__name__)
Expand Down Expand Up @@ -41,8 +45,12 @@ class UDCTokenSettings(ConfigMapping):
def __init__(self, loaded_yaml: dict):
udc_settings = ((loaded_yaml.get("settings") or {}).get("services") or {}).get("udc") or {}
super(UDCTokenSettings, self).__init__(udc_settings.get("token"))
self.validate()
print(self.dict)
eorituz marked this conversation as resolved.
Show resolved Hide resolved

def validate(self):
self.assert_option(self.max_funding >= self.balance_per_node, UDCTokenConfigError)

@property
def deposit(self):
return self.get("deposit", False)
Expand Down
7 changes: 6 additions & 1 deletion scenario_player/utils/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,10 @@ def effective_balance(self, at_target):
"""Get the effective balance of the target address."""
return self.contract_proxy.contract.functions.effectiveBalance(at_target).call()

def total_deposit(self, at_target):
""""Get the so far deposted amount"""
return self.contract_proxy.contract.functions.total_deposit(at_target).call()

def mint(self, target_address) -> Union[str, None]:
"""The mint function isn't present on the UDC, pass the UDTC address instead."""
return super(UserDepositContract, self).mint(
Expand Down Expand Up @@ -397,6 +401,7 @@ def deposit(self, target_address) -> Union[str, None]:
TODO: Allow setting max funding parameter, similar to the token `funding_min` setting.
"""
balance = self.effective_balance(target_address)
total_deposit = self.total_deposit(target_address)
min_deposit = self.config.settings.services.udc.token.balance_per_node
max_funding = self.config.settings.services.udc.token.max_funding
log.debug(
Expand All @@ -409,6 +414,6 @@ def deposit(self, target_address) -> Union[str, None]:
return

log.debug("deposit call required - insufficient funds")
deposit_amount = max_funding - balance
deposit_amount = total_deposit + (max_funding - balance)
params = {"amount": deposit_amount, "target_address": target_address}
return self.transact("deposit", params)
28 changes: 26 additions & 2 deletions tests/unittests/utils/configuration/test_settings.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from unittest.mock import patch

import pytest
import yaml
from web3.gas_strategies.time_based import fast_gas_price_strategy, medium_gas_price_strategy

from scenario_player.exceptions.config import InsufficientMintingAmount, UDCTokenConfigError
from scenario_player.scenario import ScenarioYAML
from scenario_player.utils.configuration.base import ConfigMapping
from scenario_player.utils.configuration.settings import (
PFSSettingsConfig,
Expand All @@ -14,6 +15,16 @@
)


@pytest.fixture()
def file_for_insufficient_minting_test(tmp_path, minimal_yaml_dict):
minimal_yaml_dict["settings"] = {"services": {"udc": {"token": {"max_funding": 6000}}}}
minimal_yaml_dict["token"] = {"min_balance": 5999}
tmp_file = tmp_path.joinpath("tmp.yaml")
with open(tmp_file, "w") as outfile:
yaml.dump(minimal_yaml_dict, outfile, default_flow_style=False)
yield tmp_file


class TestSettingsConfig:
def test_is_subclass_of_config_mapping(self, minimal_yaml_dict):
"""The class is a subclass of :class:`ConfigMapping`."""
Expand Down Expand Up @@ -158,3 +169,16 @@ def test_attributes_whose_key_is_absent_return_expected_default(
config = UDCTokenSettings(minimal_yaml_dict)
MISSING = object()
assert getattr(config, key, MISSING) == expected

def test_balance_per_node_must_not_be_greater_than_max_funding(self, minimal_yaml_dict):
minimal_yaml_dict["settings"] = {
"services": {"udc": {"token": {"max_funding": 6000, "balance_per_node": 6001}}}
}
with pytest.raises(UDCTokenConfigError):
UDCTokenSettings(minimal_yaml_dict)

def test_insufficient_minting(self, file_for_insufficient_minting_test):
with pytest.raises(InsufficientMintingAmount):
ScenarioYAML(
file_for_insufficient_minting_test, file_for_insufficient_minting_test.parent
)