Merge pull request #1456 from vzotova/pagination

Pagination for `getAllActiveStakers` method
pull/1477/head
K Prasch 2019-11-20 11:34:45 -08:00 committed by GitHub
commit 2d1add0e53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 231 additions and 73 deletions

View File

@ -185,6 +185,8 @@ class StakingEscrowAgent(EthereumContractAgent):
registry_contract_name = STAKING_ESCROW_CONTRACT_NAME
_proxy_name = DISPATCHER_CONTRACT_NAME
DEFAULT_PAGINATION_SIZE = 30 # TODO test on goerli
class NotEnoughStakers(Exception):
pass
@ -228,12 +230,34 @@ class StakingEscrowAgent(EthereumContractAgent):
return active_stakers, pending_stakers, missing_stakers
def get_all_locked_tokens(self, periods: int) -> int:
"""Returns the current period"""
def get_all_active_stakers(self, periods: int, pagination_size: int = None) -> Tuple[int, list]:
"""Only stakers which confirmed the current period (in the previous period) are used."""
if not periods > 0:
raise ValueError("Period must be > 0")
all_locked_tokens, _stakers = self.contract.functions.getAllActiveStakers(periods).call()
if pagination_size is None:
pagination_size = StakingEscrowAgent.DEFAULT_PAGINATION_SIZE if self.blockchain.is_light else 0
elif pagination_size < 0:
raise ValueError("Pagination size must be >= 0")
if pagination_size > 0:
num_stakers = self.get_staker_population()
start_index = 0
n_tokens = 0
stakers = list()
while start_index < num_stakers:
temp_locked_tokens, temp_stakers = \
self.contract.functions.getActiveStakers(periods, start_index, pagination_size).call()
n_tokens += temp_locked_tokens
stakers += temp_stakers
start_index += pagination_size
else:
n_tokens, stakers = self.contract.functions.getActiveStakers(periods, 0, 0).call()
return n_tokens, stakers
def get_all_locked_tokens(self, periods: int, pagination_size: int = None) -> int:
all_locked_tokens, _stakers = self.get_all_active_stakers(periods=periods, pagination_size=pagination_size)
return all_locked_tokens
#
@ -464,7 +488,13 @@ class StakingEscrowAgent(EthereumContractAgent):
staker_address = self.contract.functions.stakers(index).call()
yield staker_address
def sample(self, quantity: int, duration: int, additional_ursulas: float = 1.5, attempts: int = 5) -> List[str]:
def sample(self,
quantity: int,
duration: int,
additional_ursulas:float = 1.5,
attempts: int = 5,
pagination_size: int = None
) -> List[str]:
"""
Select n random Stakers, according to their stake distribution.
@ -487,7 +517,7 @@ class StakingEscrowAgent(EthereumContractAgent):
"""
system_random = random.SystemRandom()
n_tokens, stakers = self.contract.functions.getAllActiveStakers(duration).call()
n_tokens, stakers = self.get_all_active_stakers(periods=duration, pagination_size=pagination_size)
if n_tokens == 0:
raise self.NotEnoughStakers('There are no locked tokens for duration {}.'.format(duration))
@ -506,8 +536,6 @@ class StakingEscrowAgent(EthereumContractAgent):
while staker_index < stakers_len and point_index < sample_size:
current_staker = stakers[staker_index][0]
staker_tokens = stakers[staker_index][1]
if staker_tokens == 0: # No active stakers left
break
next_sum_value = sum_of_locked_tokens + staker_tokens
point = points[point_index]

View File

@ -95,6 +95,7 @@ class BlockchainInterface:
def __init__(self,
poa: bool = True,
light: bool = False,
provider_process: NuCypherGethProcess = NO_PROVIDER_PROCESS,
provider_uri: str = NO_BLOCKCHAIN_CONNECTION,
provider: Web3Providers = NO_BLOCKCHAIN_CONNECTION):
@ -173,6 +174,7 @@ class BlockchainInterface:
self.w3 = NO_BLOCKCHAIN_CONNECTION
self.client = NO_BLOCKCHAIN_CONNECTION
self.transacting_power = READ_ONLY_INTERFACE
self.is_light = light
def __repr__(self):
r = '{name}({uri})'.format(name=self.__class__.__name__, uri=self.provider_uri)
@ -185,7 +187,7 @@ class BlockchainInterface:
return blockchain
def to_dict(self) -> dict:
payload = dict(provider_uri=self.provider_uri, poa=self.poa)
payload = dict(provider_uri=self.provider_uri, poa=self.poa, light=self.is_light)
return payload
@property

View File

@ -329,22 +329,28 @@ contract StakingEscrow is Issuer {
* @notice Get the value of locked tokens for active stakers in (getCurrentPeriod() + _periods) period
* as well as stakers and their locked tokens
* @param _periods Amount of periods for locked tokens calculation
* @param _startIndex Start index for looking in stakers array
* @param _maxStakers Max stakers for looking, if set 0 then all will be used
* @return allLockedTokens Sum of locked tokens for active stakers
* @return activeStakers Array of stakers and their locked tokens. Stakers addresses stored as uint256
**/
function getAllActiveStakers(uint16 _periods)
function getActiveStakers(uint16 _periods, uint256 _startIndex, uint256 _maxStakers)
external view returns (uint256 allLockedTokens, uint256[2][] memory activeStakers)
{
require(_periods > 0);
uint256 stakersLength = stakers.length;
activeStakers = new uint256[2][](stakersLength);
uint256 resultIndex = 0;
uint256 endIndex = stakers.length;
require(_startIndex < endIndex);
if (_maxStakers != 0 && _startIndex + _maxStakers < endIndex) {
endIndex = _startIndex + _maxStakers;
}
activeStakers = new uint256[2][](endIndex - _startIndex);
uint256 resultIndex = 0;
uint16 currentPeriod = getCurrentPeriod();
uint16 nextPeriod = currentPeriod.add16(_periods);
for (uint256 i = 0; i < stakersLength; i++) {
for (uint256 i = _startIndex; i < endIndex; i++) {
address staker = stakers[i];
StakerInfo storage info = stakerInfo[staker];
if (info.confirmedPeriod1 != currentPeriod &&
@ -358,6 +364,9 @@ contract StakingEscrow is Issuer {
allLockedTokens = allLockedTokens.add(lockedTokens);
}
}
assembly {
mstore(activeStakers, resultIndex)
}
}
/**

View File

@ -55,6 +55,7 @@ def alice():
@_admin_options
@click.option('--config-root', help="Custom configuration directory", type=click.Path())
@click.option('--poa', help="Inject POA middleware", is_flag=True, default=None)
@click.option('--light', help="Indicate that node is light", is_flag=True, default=False)
@click.option('--m', help="M-Threshold KFrags", type=click.INT)
@click.option('--n', help="N-Total KFrags", type=click.INT)
@click.option('--rate', help="Policy rate per period in wei", type=click.FLOAT)
@ -72,7 +73,7 @@ def init(click_config,
registry_filepath,
# Other
config_root, poa, m, n, rate, duration_periods):
config_root, poa, light, m, n, rate, duration_periods):
"""
Create a brand new persistent Alice.
"""
@ -115,6 +116,7 @@ def init(click_config,
registry_filepath=registry_filepath,
provider_process=ETH_NODE,
poa=poa,
light=light,
provider_uri=provider_uri,
m=m,
n=n,

View File

@ -46,6 +46,7 @@ from nucypher.config.characters import StakeHolderConfiguration
# Args (poa, registry_filepath)
def _admin_options(func):
@click.option('--poa', help="Inject POA middleware", is_flag=True)
@click.option('--light', help="Indicate that node is light", is_flag=True, default=False)
@click.option('--registry-filepath', help="Custom contract registry filepath", type=EXISTING_READABLE_FILE)
@functools.wraps(func)
def wrapper(*args, **kwargs):
@ -116,7 +117,7 @@ def init_stakeholder(click_config,
config_root, force,
# Admin Options
poa, registry_filepath):
poa, light, registry_filepath):
"""
Create a new stakeholder configuration.
"""
@ -125,6 +126,7 @@ def init_stakeholder(click_config,
new_stakeholder = StakeHolderConfiguration.generate(config_root=config_root,
provider_uri=provider_uri,
poa=poa,
light=light,
sync=False,
registry_filepath=registry_filepath)
@ -139,7 +141,7 @@ def init_stakeholder(click_config,
def list(click_config,
# API Options
poa, registry_filepath, config_file, provider_uri, staking_address,
poa, light, registry_filepath, config_file, provider_uri, staking_address,
# Other options
all
@ -151,8 +153,14 @@ def list(click_config,
### Setup ###
emitter = _setup_emitter(click_config)
STAKEHOLDER, blockchain = _create_stakeholder(config_file, provider_uri, poa, registry_filepath, staking_address,
beneficiary_address=None, allocation_filepath=None)
STAKEHOLDER, blockchain = _create_stakeholder(config_file,
provider_uri,
poa,
light,
registry_filepath,
staking_address,
beneficiary_address=None,
allocation_filepath=None)
#############
painting.paint_stakes(emitter=emitter, stakes=STAKEHOLDER.all_stakes, paint_inactive=all)
@ -164,7 +172,7 @@ def list(click_config,
def accounts(click_config,
# API Options
poa, registry_filepath, config_file, provider_uri, staking_address):
poa, light, registry_filepath, config_file, provider_uri, staking_address):
"""
Show ETH and NU balances for stakeholder's accounts.
"""
@ -172,8 +180,14 @@ def accounts(click_config,
### Setup ###
emitter = _setup_emitter(click_config)
STAKEHOLDER, blockchain = _create_stakeholder(config_file, provider_uri, poa, registry_filepath, staking_address,
beneficiary_address=None, allocation_filepath=None)
STAKEHOLDER, blockchain = _create_stakeholder(config_file,
provider_uri,
poa,
light,
registry_filepath,
staking_address,
beneficiary_address=None,
allocation_filepath=None)
#############
painting.paint_accounts(emitter=emitter, balances=STAKEHOLDER.wallet.balances)
@ -186,7 +200,7 @@ def accounts(click_config,
def set_worker(click_config,
# Worker Options
poa, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
poa, light, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
beneficiary_address, allocation_filepath,
worker_address,
@ -199,7 +213,12 @@ def set_worker(click_config,
### Setup ###
emitter = _setup_emitter(click_config)
STAKEHOLDER, blockchain = _create_stakeholder(config_file, provider_uri, poa, registry_filepath, staking_address,
STAKEHOLDER, blockchain = _create_stakeholder(config_file,
provider_uri,
poa,
light,
registry_filepath,
staking_address,
beneficiary_address=beneficiary_address,
allocation_filepath=allocation_filepath)
#############
@ -250,7 +269,7 @@ def set_worker(click_config,
def detach_worker(click_config,
# Worker Options
poa, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
poa, light, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
beneficiary_address, allocation_filepath,
worker_address,
@ -263,7 +282,12 @@ def detach_worker(click_config,
### Setup ###
emitter = _setup_emitter(click_config)
STAKEHOLDER, blockchain = _create_stakeholder(config_file, provider_uri, poa, registry_filepath, staking_address,
STAKEHOLDER, blockchain = _create_stakeholder(config_file,
provider_uri,
poa,
light,
registry_filepath,
staking_address,
beneficiary_address=beneficiary_address,
allocation_filepath=allocation_filepath)
#############
@ -312,7 +336,7 @@ def detach_worker(click_config,
def create(click_config,
# Stake Options
poa, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
poa, light, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
beneficiary_address, allocation_filepath,
# Other
@ -324,7 +348,12 @@ def create(click_config,
### Setup ###
emitter = _setup_emitter(click_config)
STAKEHOLDER, blockchain = _create_stakeholder(config_file, provider_uri, poa, registry_filepath, staking_address,
STAKEHOLDER, blockchain = _create_stakeholder(config_file,
provider_uri,
poa,
light,
registry_filepath,
staking_address,
beneficiary_address=beneficiary_address,
allocation_filepath=allocation_filepath)
#############
@ -398,7 +427,7 @@ def create(click_config,
def restake(click_config,
# Stake Options
poa, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
poa, light, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
beneficiary_address, allocation_filepath,
# Other
@ -410,7 +439,12 @@ def restake(click_config,
### Setup ###
emitter = _setup_emitter(click_config)
STAKEHOLDER, blockchain = _create_stakeholder(config_file, provider_uri, poa, registry_filepath, staking_address,
STAKEHOLDER, blockchain = _create_stakeholder(config_file,
provider_uri,
poa,
light,
registry_filepath,
staking_address,
beneficiary_address=beneficiary_address,
allocation_filepath=allocation_filepath)
#############
@ -458,7 +492,7 @@ def restake(click_config,
def divide(click_config,
# Stake Options
poa, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
poa, light, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
beneficiary_address, allocation_filepath,
# Other
@ -470,7 +504,12 @@ def divide(click_config,
### Setup ###
emitter = _setup_emitter(click_config)
STAKEHOLDER, blockchain = _create_stakeholder(config_file, provider_uri, poa, registry_filepath, staking_address,
STAKEHOLDER, blockchain = _create_stakeholder(config_file,
provider_uri,
poa,
light,
registry_filepath,
staking_address,
beneficiary_address=beneficiary_address,
allocation_filepath=allocation_filepath)
#############
@ -547,7 +586,7 @@ def divide(click_config,
def collect_reward(click_config,
# Stake Options
poa, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
poa, light, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
beneficiary_address, allocation_filepath,
# Other
@ -559,7 +598,12 @@ def collect_reward(click_config,
### Setup ###
emitter = _setup_emitter(click_config)
STAKEHOLDER, blockchain = _create_stakeholder(config_file, provider_uri, poa, registry_filepath, staking_address,
STAKEHOLDER, blockchain = _create_stakeholder(config_file,
provider_uri,
poa,
light,
registry_filepath,
staking_address,
beneficiary_address=beneficiary_address,
allocation_filepath=allocation_filepath)
#############
@ -605,11 +649,12 @@ def _setup_emitter(click_config):
return emitter
def _get_stakeholder_config(config_file, provider_uri, poa, registry_filepath):
def _get_stakeholder_config(config_file, provider_uri, poa, light, registry_filepath):
try:
stakeholder_config = StakeHolderConfiguration.from_configuration_file(filepath=config_file,
provider_uri=provider_uri,
poa=poa,
light=light,
sync=False,
registry_filepath=registry_filepath)
@ -619,9 +664,9 @@ def _get_stakeholder_config(config_file, provider_uri, poa, registry_filepath):
config_file=config_file)
def _create_stakeholder(config_file, provider_uri, poa, registry_filepath,
def _create_stakeholder(config_file, provider_uri, poa, light, registry_filepath,
staking_address, beneficiary_address, allocation_filepath):
stakeholder_config = _get_stakeholder_config(config_file, provider_uri, poa, registry_filepath)
stakeholder_config = _get_stakeholder_config(config_file, provider_uri, poa, light, registry_filepath)
# Now let's check whether we're dealing here with a regular staker or a preallocation staker
is_preallocation_staker = (beneficiary_address and staking_address) or allocation_filepath

View File

@ -58,6 +58,7 @@ def _admin_options(func):
@click.option('--rest-port', help="The host port to run Ursula network services on", type=NETWORK_PORT)
@click.option('--db-filepath', help="The database filepath to connect to", type=click.STRING)
@click.option('--poa', help="Inject POA middleware", is_flag=True, default=None)
@click.option('--light', help="Indicate that node is light", is_flag=True, default=False)
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
@ -98,7 +99,7 @@ def init(click_config,
# Admin Options
geth, provider_uri, network, registry_filepath, staker_address, worker_address, federated_only, rest_host,
rest_port, db_filepath, poa,
rest_port, db_filepath, poa, light,
# Other
force, config_root):
@ -143,7 +144,8 @@ def init(click_config,
registry_filepath=registry_filepath,
provider_process=ETH_NODE,
provider_uri=provider_uri,
poa=poa)
poa=poa,
light=light)
painting.paint_new_installation_help(emitter, new_configuration=ursula_config)
@ -157,7 +159,7 @@ def destroy(click_config,
# Admin Options
geth, provider_uri, network, registry_filepath, staker_address, worker_address, federated_only, rest_host,
rest_port, db_filepath, poa,
rest_port, db_filepath, poa, light,
# Other
config_file, force, dev):
@ -174,7 +176,7 @@ def destroy(click_config,
ursula_config, provider_uri = _get_ursula_config(emitter, geth, provider_uri, network, registry_filepath, dev,
config_file, staker_address, worker_address, federated_only,
rest_host, rest_port, db_filepath, poa)
rest_host, rest_port, db_filepath, poa, light)
#############
actions.destroy_configuration(emitter, character_config=ursula_config, force=force)
@ -189,7 +191,7 @@ def forget(click_config,
# Admin Options
geth, provider_uri, network, registry_filepath, staker_address, worker_address, federated_only, rest_host,
rest_port, db_filepath, poa,
rest_port, db_filepath, poa, light,
# Other
config_file, dev):
@ -205,7 +207,7 @@ def forget(click_config,
ursula_config, provider_uri = _get_ursula_config(emitter, geth, provider_uri, network, registry_filepath, dev,
config_file, staker_address, worker_address, federated_only,
rest_host, rest_port, db_filepath, poa)
rest_host, rest_port, db_filepath, poa, light)
#############
actions.forget(emitter, configuration=ursula_config)
@ -221,7 +223,7 @@ def run(click_config,
# API Options
geth, provider_uri, network, registry_filepath, staker_address, worker_address, federated_only, rest_host,
rest_port, db_filepath, poa, config_file, dev, lonely, teacher_uri, min_stake,
rest_port, db_filepath, poa, light, config_file, dev, lonely, teacher_uri, min_stake,
# Other
interactive, dry_run):
@ -238,7 +240,7 @@ def run(click_config,
ursula_config, provider_uri = _get_ursula_config(emitter, geth, provider_uri, network, registry_filepath, dev,
config_file, staker_address, worker_address, federated_only,
rest_host, rest_port, db_filepath, poa)
rest_host, rest_port, db_filepath, poa, light)
#############
URSULA = _create_ursula(ursula_config, click_config, dev, emitter, lonely, teacher_uri, min_stake)
@ -297,7 +299,7 @@ def save_metadata(click_config,
# API Options
geth, provider_uri, network, registry_filepath, staker_address, worker_address, federated_only,
rest_host, rest_port, db_filepath, poa, config_file, dev, lonely, teacher_uri, min_stake):
rest_host, rest_port, db_filepath, poa, light, config_file, dev, lonely, teacher_uri, min_stake):
"""
Manually write node metadata to disk without running.
"""
@ -310,7 +312,7 @@ def save_metadata(click_config,
ursula_config, provider_uri = _get_ursula_config(emitter, geth, provider_uri, network, registry_filepath, dev,
config_file, staker_address, worker_address, federated_only,
rest_host, rest_port, db_filepath, poa)
rest_host, rest_port, db_filepath, poa, light)
#############
URSULA = _create_ursula(ursula_config, click_config, dev, emitter, lonely, teacher_uri, min_stake)
@ -326,7 +328,7 @@ def view(click_config,
# API Options
geth, provider_uri, network, registry_filepath, staker_address, worker_address, federated_only, rest_host,
rest_port, db_filepath, poa, config_file, dev, lonely, teacher_uri, min_stake):
rest_port, db_filepath, poa, light, config_file, dev, lonely, teacher_uri, min_stake):
"""
View the Ursula node's configuration.
"""
@ -340,7 +342,7 @@ def view(click_config,
ursula_config, provider_uri = _get_ursula_config(emitter, geth, provider_uri, network, registry_filepath, dev,
config_file, staker_address, worker_address, federated_only,
rest_host, rest_port, db_filepath, poa)
rest_host, rest_port, db_filepath, poa, light)
#############
URSULA = _create_ursula(ursula_config, click_config, dev, emitter, lonely, teacher_uri, min_stake)
@ -369,7 +371,7 @@ def confirm_activity(click_config,
# API Options
geth, provider_uri, network, registry_filepath, staker_address, worker_address, federated_only,
rest_host, rest_port, db_filepath, poa, config_file, dev, lonely, teacher_uri, min_stake):
rest_host, rest_port, db_filepath, poa, light, config_file, dev, lonely, teacher_uri, min_stake):
"""
Manually confirm-activity for the current period.
"""
@ -383,7 +385,7 @@ def confirm_activity(click_config,
ursula_config, provider_uri = _get_ursula_config(emitter, geth, provider_uri, network, registry_filepath, dev,
config_file, staker_address, worker_address, federated_only,
rest_host, rest_port, db_filepath, poa)
rest_host, rest_port, db_filepath, poa, light)
#############
URSULA = _create_ursula(ursula_config, click_config, dev, emitter, lonely, teacher_uri, min_stake)
@ -440,7 +442,7 @@ def _pre_launch_warnings(emitter, dev, force):
def _get_ursula_config(emitter, geth, provider_uri, network, registry_filepath, dev, config_file,
staker_address, worker_address, federated_only, rest_host, rest_port, db_filepath, poa):
staker_address, worker_address, federated_only, rest_host, rest_port, db_filepath, poa, light):
ETH_NODE = NO_BLOCKCHAIN_CONNECTION
if geth:
@ -451,6 +453,7 @@ def _get_ursula_config(emitter, geth, provider_uri, network, registry_filepath,
ursula_config = UrsulaConfiguration(dev_mode=True,
domains={TEMPORARY_DOMAIN},
poa=poa,
light=light,
registry_filepath=registry_filepath,
provider_process=ETH_NODE,
provider_uri=provider_uri,
@ -471,6 +474,7 @@ def _get_ursula_config(emitter, geth, provider_uri, network, registry_filepath,
rest_port=rest_port,
db_filepath=db_filepath,
poa=poa,
light=light,
federated_only=federated_only)
except FileNotFoundError:
return actions.handle_missing_configuration_file(character_config_class=UrsulaConfiguration,

View File

@ -34,6 +34,7 @@ def _common_options(func):
@click.option('--provider', 'provider_uri', help="Blockchain provider's URI", type=click.STRING, default="auto://")
@click.option('--geth', '-G', help="Run using the built-in geth node", is_flag=True)
@click.option('--poa', help="Inject POA middleware", is_flag=True, default=False)
@click.option('--light', help="Indicate that node is light", is_flag=True, default=False)
@click.option('--registry-filepath', help="Custom contract registry filepath", type=EXISTING_READABLE_FILE)
@functools.wraps(func)
def wrapper(*args, **kwargs):
@ -55,13 +56,13 @@ def status():
def network(click_config,
# Common Options
provider_uri, geth, poa, registry_filepath):
provider_uri, geth, poa, light, registry_filepath):
"""
Overall information of the NuCypher Network.
"""
# Init
emitter = _setup_emitter(click_config)
staking_agent = _get_staking_agent(click_config, emitter, geth, poa, provider_uri, registry_filepath)
staking_agent = _get_staking_agent(click_config, emitter, geth, poa, light, provider_uri, registry_filepath)
paint_contract_status(staking_agent.registry, emitter=emitter)
@ -73,7 +74,7 @@ def network(click_config,
def stakers(click_config,
# Common Options
provider_uri, geth, poa, registry_filepath,
provider_uri, geth, poa, light, registry_filepath,
# Other
staking_address):
@ -82,7 +83,7 @@ def stakers(click_config,
"""
# Init
emitter = _setup_emitter(click_config)
staking_agent = _get_staking_agent(click_config, emitter, geth, poa, provider_uri, registry_filepath)
staking_agent = _get_staking_agent(click_config, emitter, geth, poa, light, provider_uri, registry_filepath)
stakers = [staking_address] if staking_address else staking_agent.get_stakers()
paint_stakers(emitter=emitter, stakers=stakers, agent=staking_agent)
@ -95,7 +96,7 @@ def stakers(click_config,
def locked_tokens(click_config,
# Common Options
provider_uri, geth, poa, registry_filepath,
provider_uri, geth, poa, light, registry_filepath,
# Other
periods):
@ -104,7 +105,7 @@ def locked_tokens(click_config,
"""
# Init
emitter = _setup_emitter(click_config)
staking_agent = _get_staking_agent(click_config, emitter, geth, poa, provider_uri, registry_filepath)
staking_agent = _get_staking_agent(click_config, emitter, geth, poa, light, provider_uri, registry_filepath)
paint_locked_tokens_status(emitter=emitter, agent=staking_agent, periods=periods)
@ -117,7 +118,7 @@ def _setup_emitter(click_config):
return emitter
def _get_staking_agent(click_config, emitter, geth, poa, provider_uri, registry_filepath):
def _get_staking_agent(click_config, emitter, geth, poa, light, provider_uri, registry_filepath):
try:
ETH_NODE = None
if geth:
@ -128,6 +129,7 @@ def _get_staking_agent(click_config, emitter, geth, poa, provider_uri, registry_
BlockchainInterfaceFactory.initialize_interface(provider_uri=provider_uri,
provider_process=ETH_NODE,
poa=poa,
light=light,
sync=False,
show_sync_progress=False)

View File

@ -256,7 +256,7 @@ class StakeHolderConfiguration(CharacterConfiguration):
"""Values to read/write from stakeholder JSON configuration files"""
payload = dict(provider_uri=self.provider_uri,
poa=self.poa,
light=self.is_light,
# TODO: Move empty collection casting to base
checksum_addresses=self.checksum_addresses or list())

View File

@ -88,6 +88,7 @@ class CharacterConfiguration(BaseConfiguration):
# Blockchain
poa: bool = False,
light: bool = False,
sync: bool = False,
provider_uri: str = None,
provider_process=None,
@ -127,6 +128,7 @@ class CharacterConfiguration(BaseConfiguration):
# Blockchain
self.poa = poa
self.is_light = light
self.provider_uri = provider_uri or NO_BLOCKCHAIN_CONNECTION
self.provider_process = provider_process or NO_BLOCKCHAIN_CONNECTION
@ -167,6 +169,7 @@ class CharacterConfiguration(BaseConfiguration):
# Clear decentralized attributes to ensure consistency with a
# federated configuration.
self.poa = False
self.is_light = False
self.provider_uri = None
self.provider_process = None
self.registry_filepath = None
@ -182,6 +185,7 @@ class CharacterConfiguration(BaseConfiguration):
BlockchainInterfaceFactory.initialize_interface(provider_uri=self.provider_uri,
poa=self.poa,
light=self.is_light,
provider_process=self.provider_process,
sync=sync,
show_sync_progress=NucypherClickConfig.verbosity)
@ -265,7 +269,7 @@ class CharacterConfiguration(BaseConfiguration):
Warning: This method allows mutation and may result in an inconsistent configuration.
"""
merged_parameters = {**self.static_payload(), **self.dynamic_payload, **overrides}
non_init_params = ('config_root', 'poa', 'provider_uri', 'registry_filepath')
non_init_params = ('config_root', 'poa', 'light', 'provider_uri', 'registry_filepath')
character_init_params = filter(lambda t: t[0] not in non_init_params, merged_parameters.items())
return dict(character_init_params)
@ -348,7 +352,7 @@ class CharacterConfiguration(BaseConfiguration):
# Optional values (mode)
if not self.federated_only:
if self.provider_uri:
payload.update(dict(provider_uri=self.provider_uri, poa=self.poa))
payload.update(dict(provider_uri=self.provider_uri, poa=self.poa, light=self.is_light))
if self.registry_filepath:
payload.update(dict(registry_filepath=self.registry_filepath))

View File

@ -88,6 +88,7 @@ class TesterBlockchain(BlockchainDeployerInterface):
def __init__(self,
test_accounts=None,
poa=True,
light=False,
eth_airdrop=False,
free_transactions=False,
compiler: SolidityCompiler = None,
@ -103,6 +104,7 @@ class TesterBlockchain(BlockchainDeployerInterface):
super().__init__(provider_uri=self._PROVIDER_URI,
provider_process=None,
poa=poa,
light=light,
compiler=self._compiler,
*args, **kwargs)

View File

@ -165,9 +165,9 @@ def test_staking(testerchain, token, escrow_contract):
assert current_period + 1 == escrow.functions.getLastActivePeriod(ursula2).call()
# No active stakers before next period
all_locked, stakers = escrow.functions.getAllActiveStakers(1).call()
all_locked, stakers = escrow.functions.getActiveStakers(1, 0, 0).call()
assert 0 == all_locked
assert 0 == stakers[0][1]
assert 0 == len(stakers)
events = activity_log.get_all_entries()
assert 2 == len(events)
@ -188,7 +188,7 @@ def test_staking(testerchain, token, escrow_contract):
assert 500 == escrow.functions.getLockedTokens(ursula2).call()
# Both stakers are active and have locked tokens in next period
all_locked, stakers = escrow.functions.getAllActiveStakers(1).call()
all_locked, stakers = escrow.functions.getActiveStakers(1, 0, 0).call()
assert 1500 == all_locked
assert 2 == len(stakers)
assert ursula1 == to_checksum_address(stakers[0][0])
@ -196,10 +196,27 @@ def test_staking(testerchain, token, escrow_contract):
assert ursula2 == to_checksum_address(stakers[1][0])
assert 500 == stakers[1][1]
# Test parameters of getActiveStakers method
same_all_locked, same_stakers = escrow.functions.getActiveStakers(1, 0, 2).call()
assert all_locked == same_all_locked
assert stakers == same_stakers
same_all_locked, same_stakers = escrow.functions.getActiveStakers(1, 0, 10).call()
assert all_locked == same_all_locked
assert stakers == same_stakers
all_locked_1, stakers_1 = escrow.functions.getActiveStakers(1, 0, 1).call()
all_locked_2, stakers_2 = escrow.functions.getActiveStakers(1, 1, 1).call()
assert all_locked == all_locked_1 + all_locked_2
assert stakers == stakers_1 + stakers_2
same_all_locked, same_stakers = escrow.functions.getActiveStakers(1, 1, 0).call()
assert all_locked_2 == same_all_locked
assert stakers_2 == same_stakers
with pytest.raises((TransactionFailed, ValueError)):
escrow.functions.getActiveStakers(1, 2, 1).call()
# But in two periods their sub stakes will be unlocked
all_locked, stakers = escrow.functions.getAllActiveStakers(2).call()
all_locked, stakers = escrow.functions.getActiveStakers(2, 0, 0).call()
assert 0 == all_locked
assert 0 == stakers[0][1]
assert 0 == len(stakers)
# Ursula's withdrawal attempt won't succeed because everything is locked
with pytest.raises((TransactionFailed, ValueError)):
@ -250,24 +267,30 @@ def test_staking(testerchain, token, escrow_contract):
testerchain.wait_for_receipt(tx)
# Both stakers are active and only the first one locked tokens for two more periods
all_locked, stakers = escrow.functions.getAllActiveStakers(2).call()
all_locked, stakers = escrow.functions.getActiveStakers(2, 0, 0).call()
assert 500 == all_locked
assert 2 == len(stakers)
assert 1 == len(stakers)
assert ursula1 == to_checksum_address(stakers[0][0])
assert 500 == stakers[0][1]
assert 0 == stakers[1][1]
_, stakers = escrow.functions.getActiveStakers(2, 0, 2).call()
assert 1 == len(stakers)
same_all_locked, same_stakers = escrow.functions.getActiveStakers(2, 0, 1).call()
assert all_locked == same_all_locked
assert stakers == same_stakers
all_locked, stakers = escrow.functions.getActiveStakers(2, 1, 1).call()
assert 0 == all_locked
assert 0 == len(stakers)
# Wait 1 period and checks locking
testerchain.time_travel(hours=1)
assert 1500 == escrow.functions.getLockedTokens(ursula1).call()
# Only one staker is active
all_locked, stakers = escrow.functions.getAllActiveStakers(1).call()
all_locked, stakers = escrow.functions.getActiveStakers(1, 0, 0).call()
assert 500 == all_locked
assert 2 == len(stakers)
assert 1 == len(stakers)
assert ursula1 == to_checksum_address(stakers[0][0])
assert 500 == stakers[0][1]
assert 0 == stakers[1][1]
# Confirm activity and wait 1 period, locking will be decreased because of end of one stake
tx = escrow.functions.confirmActivity().transact({'from': ursula1})

View File

@ -163,6 +163,17 @@ def test_sample_stakers(agency):
assert len(stakers) == 3 # Three...
assert len(set(stakers)) == 3 # ...unique addresses
# Same but with pagination
stakers = staking_agent.sample(quantity=3, duration=5, pagination_size=1)
assert len(stakers) == 3
assert len(set(stakers)) == 3
light = staking_agent.blockchain.is_light
staking_agent.blockchain.is_light = not light
stakers = staking_agent.sample(quantity=3, duration=5)
assert len(stakers) == 3
assert len(set(stakers)) == 3
staking_agent.blockchain.is_light = light
def test_get_current_period(agency, testerchain):
_token_agent, staking_agent,_policy_agent = agency

View File

@ -33,8 +33,9 @@ from nucypher.utilities.sandbox.constants import (
@pytest.fixture()
def another_testerchain(solidity_compiler):
testerchain = _TesterBlockchain(eth_airdrop=True, free_transactions=True)
testerchain = _TesterBlockchain(eth_airdrop=True, free_transactions=True, light=True)
testerchain.deployer_address = testerchain.etherbase_account
assert testerchain.is_light
yield testerchain

View File

@ -96,3 +96,28 @@ def test_nucypher_status_stakers(click_runner, testerchain, test_registry, agenc
assert re.search(r"Staked: " + str(round(locked_tokens, 2)), result.output, re.MULTILINE)
def test_nucypher_status_locked_tokens(click_runner, testerchain, test_registry, agency, stakers):
staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=test_registry)
# All workers confirm activity
for ursula in testerchain.ursulas_accounts:
staking_agent.confirm_activity(worker_address=ursula)
testerchain.time_travel(periods=1)
periods = 2
status_command = ('locked-tokens',
'--registry-filepath', MOCK_REGISTRY_FILEPATH,
'--provider', TEST_PROVIDER_URI,
'--poa',
'--periods', periods)
initial_light_parameter = testerchain.is_light
light_parameter = [False, True]
for light in light_parameter:
testerchain.is_light = light
result = click_runner.invoke(status, status_command, catch_exceptions=False)
assert result.exit_code == 0
current_period = staking_agent.get_current_period()
all_locked = NU.from_nunits(staking_agent.get_global_locked_tokens(at_period=current_period))
assert re.search(f"Locked Tokens for next {periods} periods", result.output, re.MULTILINE)
assert re.search(f"Min: {all_locked} - Max: {all_locked}", result.output, re.MULTILINE)