Merging #2128, #2137, #2155 into a rebase over main (instead of three separate github-generated merge commits, which caused a conflict).

pull/2175/head
jMyles 2020-08-01 00:46:19 -07:00
commit a6a873482f
4 changed files with 67 additions and 16 deletions

View File

@ -20,9 +20,7 @@ import json
import os import os
import sys import sys
import time import time
from constant_sorrow.constants import FULL, NO_WORKER_BONDED, WORKER_NOT_RUNNING
from decimal import Decimal from decimal import Decimal
from typing import Dict, List, Optional, Tuple
from web3.types import TxReceipt from web3.types import TxReceipt
import traceback import traceback
import click import click
@ -894,6 +892,47 @@ class Staker(NucypherTokenActor):
stakes = sorted(filtered_stakes, key=lambda s: s.address_index_ordering_key) stakes = sorted(filtered_stakes, key=lambda s: s.address_index_ordering_key)
return stakes return stakes
@only_me
def divide_stake(self,
stake_index: int,
target_value: NU,
additional_periods: int = None,
expiration: maya.MayaDT = None) -> tuple:
# Calculate duration in periods
if additional_periods and expiration:
raise ValueError("Pass the number of lock periods or an expiration MayaDT; not both.")
# Update staking cache element
stakes = self.stakes
# Select stake to divide from local cache
try:
current_stake = stakes[stake_index]
except KeyError:
if len(stakes):
message = f"Cannot divide stake - No stake exists with index {stake_index}."
else:
message = "Cannot divide stake - There are no active stakes."
raise Stake.StakingError(message)
# Calculate stake duration in periods
if expiration:
additional_periods = datetime_to_period(datetime=expiration,
seconds_per_period=self.economics.seconds_per_period) - current_stake.final_locked_period
if additional_periods <= 0:
raise Stake.StakingError(f"New expiration {expiration} must be at least 1 period from the "
f"current stake's end period ({current_stake.final_locked_period}).")
# Do it already!
modified_stake, new_stake = current_stake.divide(target_value=target_value,
additional_periods=additional_periods)
# Update staking cache element
self.stakes.refresh()
return modified_stake, new_stake
@only_me @only_me
def initialize_stake(self, def initialize_stake(self,
amount: NU = None, amount: NU = None,
@ -1027,7 +1066,8 @@ class Staker(NucypherTokenActor):
# Calculate stake duration in periods # Calculate stake duration in periods
if expiration: if expiration:
additional_periods = datetime_to_period(datetime=expiration, seconds_per_period=self.economics.seconds_per_period) - stake.final_locked_period additional_periods = datetime_to_period(datetime=expiration,
seconds_per_period=self.economics.seconds_per_period) - current_stake.final_locked_period
if additional_periods <= 0: if additional_periods <= 0:
raise ValueError(f"New expiration {expiration} must be at least 1 period from the " raise ValueError(f"New expiration {expiration} must be at least 1 period from the "
f"current stake's end period ({stake.final_locked_period}).") f"current stake's end period ({stake.final_locked_period}).")

View File

@ -20,6 +20,8 @@ from eth_tester.exceptions import TransactionFailed
from nucypher.blockchain.eth.agents import ContractAgency, StakingEscrowAgent from nucypher.blockchain.eth.agents import ContractAgency, StakingEscrowAgent
from nucypher.blockchain.eth.token import NU, Stake from nucypher.blockchain.eth.token import NU, Stake
from nucypher.crypto.powers import TransactingPower
from tests.constants import FEE_RATE_RANGE, INSECURE_DEVELOPMENT_PASSWORD
from tests.utils.ursula import make_decentralized_ursulas from tests.utils.ursula import make_decentralized_ursulas
from nucypher.crypto.powers import TransactingPower from nucypher.crypto.powers import TransactingPower
from nucypher.blockchain.eth.utils import datetime_at_period from nucypher.blockchain.eth.utils import datetime_at_period

View File

@ -30,11 +30,6 @@ import maya
import pytest import pytest
from click.testing import CliRunner from click.testing import CliRunner
from eth_utils import to_checksum_address from eth_utils import to_checksum_address
from sqlalchemy.engine import create_engine
from twisted.internet import defer
from twisted.internet.defer import Deferred
from twisted.logger import Logger
from io import StringIO
from web3 import Web3 from web3 import Web3
from nucypher.blockchain.economics import BaseEconomics, StandardTokenEconomics from nucypher.blockchain.economics import BaseEconomics, StandardTokenEconomics
@ -429,7 +424,6 @@ def lonely_ursula_maker(ursula_federated_test_config):
# #
def make_token_economics(blockchain): def make_token_economics(blockchain):
# Get current blocktime # Get current blocktime
now = blockchain.w3.eth.getBlock(block_identifier='latest').timestamp now = blockchain.w3.eth.getBlock(block_identifier='latest').timestamp
@ -445,7 +439,7 @@ def make_token_economics(blockchain):
economics = StandardTokenEconomics( economics = StandardTokenEconomics(
worklock_boosting_refund_rate=200, worklock_boosting_refund_rate=200,
worklock_commitment_duration=60, # periods worklock_commitment_duration=60, # periods
worklock_supply=10*BaseEconomics._default_maximum_allowed_locked, worklock_supply=10 * BaseEconomics._default_maximum_allowed_locked,
bidding_start_date=bidding_start_date, bidding_start_date=bidding_start_date,
bidding_end_date=bidding_end_date, bidding_end_date=bidding_end_date,
cancellation_end_date=cancellation_end_date, cancellation_end_date=cancellation_end_date,
@ -583,11 +577,11 @@ def _make_agency(testerchain,
registry=test_registry) registry=test_registry)
worklock_deployer.deploy() worklock_deployer.deploy()
token_agent = token_deployer.make_agent() # 1 Token token_agent = token_deployer.make_agent() # 1 Token
staking_agent = staking_escrow_deployer.make_agent() # 2 Staking Escrow staking_agent = staking_escrow_deployer.make_agent() # 2 Staking Escrow
policy_agent = policy_manager_deployer.make_agent() # 3 Policy Agent policy_agent = policy_manager_deployer.make_agent() # 3 Policy Agent
_adjudicator_agent = adjudicator_deployer.make_agent() # 4 Adjudicator _adjudicator_agent = adjudicator_deployer.make_agent() # 4 Adjudicator
_worklock_agent = worklock_deployer.make_agent() # 5 Worklock _worklock_agent = worklock_deployer.make_agent() # 5 Worklock
# Set additional parameters # Set additional parameters
minimum, default, maximum = FEE_RATE_RANGE minimum, default, maximum = FEE_RATE_RANGE
@ -685,6 +679,8 @@ def stakers(testerchain, agency, token_economics, test_registry):
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def blockchain_ursulas(testerchain, stakers, ursula_decentralized_test_config): def blockchain_ursulas(testerchain, stakers, ursula_decentralized_test_config):
if MOCK_KNOWN_URSULAS_CACHE:
raise RuntimeError("Ursulas cache was unclear at fixture loading time. Did you use one of the ursula maker functions without cleaning up?")
_ursulas = make_decentralized_ursulas(ursula_config=ursula_decentralized_test_config, _ursulas = make_decentralized_ursulas(ursula_config=ursula_decentralized_test_config,
stakers_addresses=testerchain.stakers_accounts, stakers_addresses=testerchain.stakers_accounts,
workers_addresses=testerchain.ursulas_accounts, workers_addresses=testerchain.ursulas_accounts,
@ -897,7 +893,8 @@ def manual_staker(testerchain, agency):
address = '0xaaa23A5c74aBA6ca5E7c09337d5317A7C4563075' address = '0xaaa23A5c74aBA6ca5E7c09337d5317A7C4563075'
if address not in testerchain.client.accounts: if address not in testerchain.client.accounts:
staker_private_key = '13378db1c2af06933000504838afc2d52efa383206454deefb1836f8f4cd86f8' staker_private_key = '13378db1c2af06933000504838afc2d52efa383206454deefb1836f8f4cd86f8'
address = testerchain.provider.ethereum_tester.add_account(staker_private_key, password=INSECURE_DEVELOPMENT_PASSWORD) address = testerchain.provider.ethereum_tester.add_account(staker_private_key,
password=INSECURE_DEVELOPMENT_PASSWORD)
tx = {'to': address, tx = {'to': address,
'from': testerchain.etherbase_account, 'from': testerchain.etherbase_account,
@ -994,6 +991,9 @@ def fleet_of_highperf_mocked_ursulas(ursula_federated_test_config, request):
ursula.known_nodes.checksum = b"This is a fleet state checksum..".hex() ursula.known_nodes.checksum = b"This is a fleet state checksum..".hex()
yield _ursulas yield _ursulas
for ursula in _ursulas:
del MOCK_KNOWN_URSULAS_CACHE[ursula.rest_interface.port]
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def highperf_mocked_alice(fleet_of_highperf_mocked_ursulas): def highperf_mocked_alice(fleet_of_highperf_mocked_ursulas):
@ -1029,6 +1029,7 @@ def highperf_mocked_bob(fleet_of_highperf_mocked_ursulas):
bob._learning_task.stop() bob._learning_task.stop()
return bob return bob
# #
# CLI # CLI
# #

View File

@ -30,6 +30,14 @@ from twisted.internet.threads import deferToThread
from nucypher.characters.lawful import Ursula from nucypher.characters.lawful import Ursula
from tests.utils.ursula import MOCK_KNOWN_URSULAS_CACHE from tests.utils.ursula import MOCK_KNOWN_URSULAS_CACHE
from nucypher.datastore.base import RecordField from nucypher.datastore.base import RecordField
import pytest_twisted
from twisted.internet import defer, reactor
from twisted.internet.threads import deferToThread, blockingCallFromThread
from nucypher.characters.lawful import Ursula
from tests.utils.middleware import SluggishLargeFleetMiddleware
from tests.utils.ursula import MOCK_KNOWN_URSULAS_CACHE
from umbral.keys import UmbralPublicKey
from tests.mock.performance_mocks import ( from tests.mock.performance_mocks import (
NotAPublicKey, NotAPublicKey,
NotARestApp, NotARestApp,