mirror of https://github.com/nucypher/nucypher.git
Merge pull request #1456 from vzotova/pagination
Pagination for `getAllActiveStakers` methodpull/1477/head
commit
2d1add0e53
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue