def test_stake_prolong(click_runner, testerchain, agency_local_registry, manual_staker, manual_worker, stakeholder_configuration_file_location): prolong_args = ('stake', 'prolong', '--config-file', stakeholder_configuration_file_location, '--index', 0, '--lock-periods', 1, '--staking-address', manual_staker, '--force') staker = Staker(is_me=True, checksum_address=manual_staker, registry=agency_local_registry) staker.refresh_stakes() stake = staker.stakes[0] old_termination = stake.final_locked_period user_input = INSECURE_DEVELOPMENT_PASSWORD result = click_runner.invoke(nucypher_cli, prolong_args, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # Ensure Integration with Stakes stake.sync() new_termination = stake.final_locked_period assert new_termination == old_termination + 1
def paint_staking_accounts(emitter, signer, registry, domain): from nucypher.blockchain.eth.actors import Staker rows = list() blockchain = BlockchainInterfaceFactory.get_interface() token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=registry) for account in signer.accounts: eth = str(Web3.fromWei(blockchain.client.get_balance(account), 'ether')) + " ETH" nu = str(NU.from_nunits(token_agent.get_balance(account))) staker = Staker(checksum_address=account, domain=domain, registry=registry) staker.refresh_stakes() is_staking = 'Yes' if bool(staker.stakes) else 'No' rows.append((is_staking, account, eth, nu)) headers = ('Staking', 'Account', 'ETH', 'NU') emitter.echo(tabulate.tabulate(rows, showindex=True, headers=headers, tablefmt="fancy_grid"))
def paint_staking_accounts(emitter, wallet, registry): from nucypher.blockchain.eth.actors import Staker rows = list() for account in wallet.accounts: eth = str(Web3.fromWei(wallet.eth_balance(account), 'ether')) + " ETH" nu = str(NU.from_nunits(wallet.token_balance(account, registry))) staker = Staker(is_me=True, checksum_address=account, registry=registry) staker.refresh_stakes() is_staking = 'Yes' if bool(staker.stakes) else 'No' rows.append((is_staking, account, eth, nu)) headers = ('Staking', 'Account', 'ETH', 'NU') emitter.echo( tabulate.tabulate(rows, showindex=True, headers=headers, tablefmt="fancy_grid"))
def test_collect_rewards_integration( click_runner, testerchain, agency_local_registry, stakeholder_configuration_file_location, blockchain_alice, blockchain_bob, random_policy_label, manual_staker, manual_worker, token_economics, mock_transacting_power_activation, policy_value, policy_rate): half_stake_time = token_economics.minimum_locked_periods // 2 # Test setup logger = Logger("Test-CLI") # Enter the Teacher's Logger, and current_period = 0 # State the initial period for incrementing staker_address = manual_staker worker_address = manual_worker staker = Staker(is_me=True, checksum_address=staker_address, registry=agency_local_registry) staker.refresh_stakes() # The staker is staking. assert staker.is_staking assert staker.stakes assert staker.worker_address == worker_address ursula_port = select_test_port() ursula = Ursula(is_me=True, checksum_address=staker_address, worker_address=worker_address, registry=agency_local_registry, rest_host='127.0.0.1', rest_port=ursula_port, network_middleware=MockRestMiddleware(), db_filepath=tempfile.mkdtemp(), domain=TEMPORARY_DOMAIN) MOCK_KNOWN_URSULAS_CACHE[ursula_port] = ursula assert ursula.worker_address == worker_address assert ursula.checksum_address == staker_address mock_transacting_power_activation(account=worker_address, password=INSECURE_DEVELOPMENT_PASSWORD) # Make a commitment for half the first stake duration for _ in range(half_stake_time): logger.debug( f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<") ursula.commit_to_next_period() testerchain.time_travel(periods=1) current_period += 1 # Alice creates a policy and grants Bob access blockchain_alice.selection_buffer = 1 M, N = 1, 1 days = 3 now = testerchain.w3.eth.getBlock('latest').timestamp expiration = maya.MayaDT(now).add(days=days - 1) blockchain_policy = blockchain_alice.grant(bob=blockchain_bob, label=random_policy_label, m=M, n=N, value=policy_value, expiration=expiration, handpicked_ursulas={ursula}) # Ensure that the handpicked Ursula was selected for the policy arrangement = list(blockchain_policy._accepted_arrangements)[0] assert arrangement.ursula == ursula # Bob learns about the new staker and joins the policy blockchain_bob.start_learning_loop() blockchain_bob.remember_node(node=ursula) blockchain_bob.join_policy(random_policy_label, bytes(blockchain_alice.stamp)) # Enrico Encrypts (of course) enrico = Enrico(policy_encrypting_key=blockchain_policy.public_key, network_middleware=MockRestMiddleware()) verifying_key = blockchain_alice.stamp.as_umbral_pubkey() for index in range(half_stake_time - 5): logger.debug( f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<") ursula.commit_to_next_period() # Encrypt random_data = os.urandom(random.randrange(20, 100)) ciphertext, signature = enrico.encrypt_message(plaintext=random_data) # Decrypt cleartexts = blockchain_bob.retrieve(ciphertext, enrico=enrico, alice_verifying_key=verifying_key, label=random_policy_label) assert random_data == cleartexts[0] # Ursula Staying online and the clock advancing testerchain.time_travel(periods=1) current_period += 1 # Finish the passage of time for the first Stake for _ in range(5): # plus the extended periods from stake division logger.debug( f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<") ursula.commit_to_next_period() testerchain.time_travel(periods=1) current_period += 1 # # WHERES THE MONEY URSULA?? - Collecting Rewards # # The address the client wants Ursula to send rewards to burner_wallet = testerchain.w3.eth.account.create( INSECURE_DEVELOPMENT_PASSWORD) # The rewards wallet is initially empty, because it is freshly created assert testerchain.client.get_balance(burner_wallet.address) == 0 # Rewards will be unlocked after the # final committed period has passed (+1). logger.debug(f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<") testerchain.time_travel(periods=1) current_period += 1 logger.debug(f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<") # At least half of the tokens are unlocked (restaking was enabled for some prior periods) assert staker.locked_tokens() >= token_economics.minimum_allowed_locked # Since we are mocking the blockchain connection, manually consume the transacting power of the Staker. mock_transacting_power_activation(account=staker_address, password=INSECURE_DEVELOPMENT_PASSWORD) # Collect Policy Fee collection_args = ('stake', 'collect-reward', '--config-file', stakeholder_configuration_file_location, '--policy-fee', '--no-staking-reward', '--staking-address', staker_address, '--withdraw-address', burner_wallet.address) result = click_runner.invoke(nucypher_cli, collection_args, input=INSECURE_DEVELOPMENT_PASSWORD, catch_exceptions=False) assert result.exit_code == 0 # Policy Fee collected_policy_fee = testerchain.client.get_balance( burner_wallet.address) expected_collection = policy_rate * 30 assert collected_policy_fee == expected_collection # Finish the passage of time... once and for all # Extended periods from stake division for _ in range(9): ursula.commit_to_next_period() current_period += 1 logger.debug( f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<") testerchain.time_travel(periods=1) # # Collect Staking Reward # balance_before_collecting = staker.token_agent.get_balance( address=staker_address) collection_args = ('stake', 'collect-reward', '--config-file', stakeholder_configuration_file_location, '--no-policy-fee', '--staking-reward', '--staking-address', staker_address, '--force') result = click_runner.invoke(nucypher_cli, collection_args, input=INSECURE_DEVELOPMENT_PASSWORD, catch_exceptions=False) assert result.exit_code == 0 # The staker has withdrawn her staking rewards assert staker.token_agent.get_balance( address=staker_address) > balance_before_collecting
def select_client_account(emitter, provider_uri: str = None, signer: Signer = None, signer_uri: str = None, wallet: Wallet = None, prompt: str = None, default: int = 0, registry=None, show_eth_balance: bool = False, show_nu_balance: bool = False, show_staking: bool = False, network: str = None, poa: bool = None) -> str: """ Interactively select an ethereum wallet account from a table of nucypher account metadata. Note: Showing ETH and/or NU balances, causes an eager blockchain connection. """ if wallet and (provider_uri or signer_uri or signer): raise ValueError( "If a wallet is provided, don't provide a signer, provider URI, or signer URI." ) # We use Wallet internally as an account management abstraction if not wallet: if signer and signer_uri: raise ValueError('Pass either signer or signer_uri but not both.') if not provider_uri and not signer_uri: raise ValueError( "At least a provider URI or signer URI is necessary to select an account" ) if provider_uri: # Lazy connect the blockchain interface if not BlockchainInterfaceFactory.is_interface_initialized( provider_uri=provider_uri): BlockchainInterfaceFactory.initialize_interface( provider_uri=provider_uri, poa=poa, emitter=emitter) if signer_uri: testnet = network != NetworksInventory.MAINNET signer = Signer.from_signer_uri(signer_uri, testnet=testnet) wallet = Wallet(provider_uri=provider_uri, signer=signer) # Display accounts info if show_nu_balance or show_staking: # Lazy registry fetching if not registry: if not network: raise ValueError("Pass network name or registry; Got neither.") registry = InMemoryContractRegistry.from_latest_publication( network=network) wallet_accounts = wallet.accounts enumerated_accounts = dict(enumerate(wallet_accounts)) if len(enumerated_accounts) < 1: emitter.echo(NO_ETH_ACCOUNTS, color='red', bold=True) raise click.Abort() # Display account info headers = ['Account'] if show_staking: headers.append('Staking') if show_eth_balance: headers.append('ETH') if show_nu_balance: headers.append('NU') rows = list() for index, account in enumerated_accounts.items(): row = [account] if show_staking: staker = Staker(is_me=True, checksum_address=account, registry=registry) staker.refresh_stakes() is_staking = 'Yes' if bool(staker.stakes) else 'No' row.append(is_staking) if show_eth_balance: ether_balance = Web3.fromWei(wallet.eth_balance(account), 'ether') row.append(f'{ether_balance} ETH') if show_nu_balance: token_balance = NU.from_nunits( wallet.token_balance(account, registry)) row.append(token_balance) rows.append(row) emitter.echo(tabulate(rows, headers=headers, showindex='always')) # Prompt the user for selection, and return prompt = prompt or GENERIC_SELECT_ACCOUNT account_range = click.IntRange(min=0, max=len(enumerated_accounts) - 1) choice = click.prompt(prompt, type=account_range, default=default) chosen_account = enumerated_accounts[choice] emitter.echo(SELECTED_ACCOUNT.format(choice=choice, chosen_account=chosen_account), color='blue') return chosen_account
def test_collect_rewards_integration( click_runner, testerchain, agency_local_registry, stakeholder_configuration_file_location, blockchain_alice, blockchain_bob, random_policy_label, manual_staker, manual_worker, token_economics, policy_value): half_stake_time = 2 * token_economics.minimum_locked_periods # Test setup logger = Logger("Test-CLI") # Enter the Teacher's Logger, and current_period = 0 # State the initial period for incrementing staker_address = manual_staker worker_address = manual_worker staker = Staker(domain=TEMPORARY_DOMAIN, checksum_address=staker_address, registry=agency_local_registry) staker.refresh_stakes() # The staker is staking. assert staker.is_staking assert staker.stakes assert staker.worker_address == worker_address ursula_port = select_test_port() ursula = Ursula(is_me=True, checksum_address=staker_address, signer=Web3Signer(testerchain.client), worker_address=worker_address, registry=agency_local_registry, rest_host=LOOPBACK_ADDRESS, rest_port=ursula_port, provider_uri=TEST_PROVIDER_URI, network_middleware=MockRestMiddleware(), db_filepath=tempfile.mkdtemp(), domain=TEMPORARY_DOMAIN) MOCK_KNOWN_URSULAS_CACHE[ursula_port] = ursula assert ursula.worker_address == worker_address assert ursula.checksum_address == staker_address # Make a commitment for half the first stake duration testerchain.time_travel(periods=1) for _ in range(half_stake_time): logger.debug( f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<") ursula.commit_to_next_period() testerchain.time_travel(periods=1) current_period += 1 # Alice creates a policy and grants Bob access blockchain_alice.selection_buffer = 1 threshold, shares = 1, 1 duration_in_periods = 3 days = (duration_in_periods - 1) * (token_economics.hours_per_period // 24) now = testerchain.w3.eth.getBlock('latest').timestamp expiration = maya.MayaDT(now).add(days=days) blockchain_policy = blockchain_alice.grant(bob=blockchain_bob, label=random_policy_label, threshold=threshold, shares=shares, value=policy_value, expiration=expiration, ursulas={ursula}) # Ensure that the handpicked Ursula was selected for the policy treasure_map = blockchain_bob._decrypt_treasure_map( blockchain_policy.treasure_map, blockchain_policy.publisher_verifying_key) assert ursula.canonical_address in treasure_map.destinations # Bob learns about the new staker and joins the policy blockchain_bob.start_learning_loop() blockchain_bob.remember_node(node=ursula) # Enrico Encrypts (of course) enrico = Enrico(policy_encrypting_key=blockchain_policy.public_key, network_middleware=MockRestMiddleware()) verifying_key = blockchain_alice.stamp.as_umbral_pubkey() for index in range(half_stake_time - 5): logger.debug( f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<") ursula.commit_to_next_period() # Encrypt random_data = os.urandom(random.randrange(20, 100)) message_kit = enrico.encrypt_message(plaintext=random_data) # Decrypt cleartexts = blockchain_bob.retrieve_and_decrypt( [message_kit], alice_verifying_key=verifying_key, encrypted_treasure_map=blockchain_policy.treasure_map) assert random_data == cleartexts[0] # Ursula Staying online and the clock advancing testerchain.time_travel(periods=1) current_period += 1 # Finish the passage of time for the first Stake for _ in range(5): # plus the extended periods from stake division logger.debug( f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<") ursula.commit_to_next_period() testerchain.time_travel(periods=1) current_period += 1 # # WHERES THE MONEY URSULA?? - Collecting Rewards # # The address the client wants Ursula to send rewards to burner_wallet = testerchain.w3.eth.account.create( INSECURE_DEVELOPMENT_PASSWORD) # The rewards wallet is initially empty, because it is freshly created assert testerchain.client.get_balance(burner_wallet.address) == 0 # Rewards will be unlocked after the # final committed period has passed (+1). logger.debug(f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<") testerchain.time_travel(periods=1) current_period += 1 logger.debug(f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<") # At least half of the tokens are unlocked (restaking was enabled for some prior periods) assert staker.locked_tokens() >= token_economics.minimum_allowed_locked # Collect Policy Fee collection_args = ('stake', 'rewards', 'withdraw', '--config-file', str(stakeholder_configuration_file_location.absolute()), '--fees', '--no-tokens', '--staking-address', staker_address, '--withdraw-address', burner_wallet.address) result = click_runner.invoke(nucypher_cli, collection_args, input=INSECURE_DEVELOPMENT_PASSWORD, catch_exceptions=False) assert result.exit_code == 0 # Policy Fee collected_policy_fee = testerchain.client.get_balance( burner_wallet.address) expected_collection = policy_value assert collected_policy_fee == expected_collection # Finish the passage of time... once and for all # Extended periods from stake division for _ in range(9): ursula.commit_to_next_period() current_period += 1 logger.debug( f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<") testerchain.time_travel(periods=1) # # Collect Staking Reward # balance_before_collecting = staker.token_agent.get_balance( address=staker_address) collection_args = ('stake', 'rewards', 'withdraw', '--config-file', str(stakeholder_configuration_file_location.absolute()), '--no-fees', '--tokens', '--staking-address', staker_address, '--force') result = click_runner.invoke(nucypher_cli, collection_args, input=INSECURE_DEVELOPMENT_PASSWORD, catch_exceptions=False) assert result.exit_code == 0 # The staker has withdrawn her staking rewards assert staker.token_agent.get_balance( address=staker_address) > balance_before_collecting