mirror of https://github.com/nucypher/nucypher.git
Merging #2128, #2137, #2155 into a rebase over main (instead of three separate github-generated merge commits, which caused a conflict).
commit
a6a873482f
|
@ -20,9 +20,7 @@ import json
|
|||
import os
|
||||
import sys
|
||||
import time
|
||||
from constant_sorrow.constants import FULL, NO_WORKER_BONDED, WORKER_NOT_RUNNING
|
||||
from decimal import Decimal
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
from web3.types import TxReceipt
|
||||
import traceback
|
||||
import click
|
||||
|
@ -894,6 +892,47 @@ class Staker(NucypherTokenActor):
|
|||
stakes = sorted(filtered_stakes, key=lambda s: s.address_index_ordering_key)
|
||||
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
|
||||
def initialize_stake(self,
|
||||
amount: NU = None,
|
||||
|
@ -1027,7 +1066,8 @@ class Staker(NucypherTokenActor):
|
|||
|
||||
# Calculate stake duration in periods
|
||||
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:
|
||||
raise ValueError(f"New expiration {expiration} must be at least 1 period from the "
|
||||
f"current stake's end period ({stake.final_locked_period}).")
|
||||
|
|
|
@ -20,6 +20,8 @@ from eth_tester.exceptions import TransactionFailed
|
|||
|
||||
from nucypher.blockchain.eth.agents import ContractAgency, StakingEscrowAgent
|
||||
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 nucypher.crypto.powers import TransactingPower
|
||||
from nucypher.blockchain.eth.utils import datetime_at_period
|
||||
|
|
|
@ -30,11 +30,6 @@ import maya
|
|||
import pytest
|
||||
from click.testing import CliRunner
|
||||
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 nucypher.blockchain.economics import BaseEconomics, StandardTokenEconomics
|
||||
|
@ -429,7 +424,6 @@ def lonely_ursula_maker(ursula_federated_test_config):
|
|||
#
|
||||
|
||||
def make_token_economics(blockchain):
|
||||
|
||||
# Get current blocktime
|
||||
now = blockchain.w3.eth.getBlock(block_identifier='latest').timestamp
|
||||
|
||||
|
@ -445,7 +439,7 @@ def make_token_economics(blockchain):
|
|||
economics = StandardTokenEconomics(
|
||||
worklock_boosting_refund_rate=200,
|
||||
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_end_date=bidding_end_date,
|
||||
cancellation_end_date=cancellation_end_date,
|
||||
|
@ -583,11 +577,11 @@ def _make_agency(testerchain,
|
|||
registry=test_registry)
|
||||
worklock_deployer.deploy()
|
||||
|
||||
token_agent = token_deployer.make_agent() # 1 Token
|
||||
staking_agent = staking_escrow_deployer.make_agent() # 2 Staking Escrow
|
||||
policy_agent = policy_manager_deployer.make_agent() # 3 Policy Agent
|
||||
_adjudicator_agent = adjudicator_deployer.make_agent() # 4 Adjudicator
|
||||
_worklock_agent = worklock_deployer.make_agent() # 5 Worklock
|
||||
token_agent = token_deployer.make_agent() # 1 Token
|
||||
staking_agent = staking_escrow_deployer.make_agent() # 2 Staking Escrow
|
||||
policy_agent = policy_manager_deployer.make_agent() # 3 Policy Agent
|
||||
_adjudicator_agent = adjudicator_deployer.make_agent() # 4 Adjudicator
|
||||
_worklock_agent = worklock_deployer.make_agent() # 5 Worklock
|
||||
|
||||
# Set additional parameters
|
||||
minimum, default, maximum = FEE_RATE_RANGE
|
||||
|
@ -685,6 +679,8 @@ def stakers(testerchain, agency, token_economics, test_registry):
|
|||
|
||||
@pytest.fixture(scope="module")
|
||||
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,
|
||||
stakers_addresses=testerchain.stakers_accounts,
|
||||
workers_addresses=testerchain.ursulas_accounts,
|
||||
|
@ -897,7 +893,8 @@ def manual_staker(testerchain, agency):
|
|||
address = '0xaaa23A5c74aBA6ca5E7c09337d5317A7C4563075'
|
||||
if address not in testerchain.client.accounts:
|
||||
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,
|
||||
'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()
|
||||
yield _ursulas
|
||||
|
||||
for ursula in _ursulas:
|
||||
del MOCK_KNOWN_URSULAS_CACHE[ursula.rest_interface.port]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
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()
|
||||
return bob
|
||||
|
||||
|
||||
#
|
||||
# CLI
|
||||
#
|
||||
|
|
|
@ -30,6 +30,14 @@ from twisted.internet.threads import deferToThread
|
|||
from nucypher.characters.lawful import Ursula
|
||||
from tests.utils.ursula import MOCK_KNOWN_URSULAS_CACHE
|
||||
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 (
|
||||
NotAPublicKey,
|
||||
NotARestApp,
|
||||
|
|
Loading…
Reference in New Issue