def blockchain_ursulas(three_agents, ursula_decentralized_test_config): token_agent, miner_agent, policy_agent = three_agents etherbase, alice, bob, *all_yall = token_agent.blockchain.interface.w3.eth.accounts ursula_addresses = all_yall[:NUMBER_OF_URSULAS_IN_DEVELOPMENT_NETWORK] token_airdrop(origin=etherbase, addresses=ursula_addresses, token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) # Leave out the last Ursula for manual stake testing *all_but_the_last_ursula, the_last_ursula = ursula_addresses _ursulas = make_decentralized_ursulas(ursula_config=ursula_decentralized_test_config, ether_addresses=all_but_the_last_ursula, stake=True) # This one is not going to stake _non_staking_ursula = make_decentralized_ursulas(ursula_config=ursula_decentralized_test_config, ether_addresses=[the_last_ursula], stake=False) _ursulas.extend(_non_staking_ursula) token_agent.blockchain.time_travel(periods=1) yield _ursulas
def blockchain_ursulas(three_agents, ursula_decentralized_test_config): token_agent, miner_agent, policy_agent = three_agents blockchain = token_agent.blockchain token_airdrop(origin=blockchain.etherbase_account, addresses=blockchain.ursulas_accounts, token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) # Leave out the last Ursula for manual stake testing *all_but_the_last_ursula, the_last_ursula = blockchain.ursulas_accounts _ursulas = make_decentralized_ursulas( ursula_config=ursula_decentralized_test_config, ether_addresses=all_but_the_last_ursula, stake=True) # This one is not going to stake _non_staking_ursula = make_decentralized_ursulas( ursula_config=ursula_decentralized_test_config, ether_addresses=[the_last_ursula], stake=False) _ursulas.extend(_non_staking_ursula) blockchain.time_travel(periods=1) yield _ursulas
def blockchain_ursulas(three_agents, ursula_decentralized_test_config): token_agent, _miner_agent, _policy_agent = three_agents blockchain = token_agent.blockchain token_airdrop(origin=blockchain.etherbase_account, addresses=blockchain.ursulas_accounts, token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) # Leave out the last Ursula for manual stake testing *all_but_the_last_ursula, the_last_ursula = blockchain.ursulas_accounts _ursulas = make_decentralized_ursulas( ursula_config=ursula_decentralized_test_config, ether_addresses=all_but_the_last_ursula, stake=True) # Stake starts next period (or else signature validation will fail) blockchain.time_travel(periods=1) # Bootstrap the network for ursula_to_teach in _ursulas: for ursula_to_learn_about in _ursulas: ursula_to_teach.remember_node(ursula_to_learn_about) # TODO: #1035 - Move non-staking Ursulas to a new fixture # This one is not going to stake _non_staking_ursula = make_decentralized_ursulas( ursula_config=ursula_decentralized_test_config, ether_addresses=[the_last_ursula], stake=False) _ursulas.extend(_non_staking_ursula) yield _ursulas
def miner(testerchain, three_agents): token_agent, miner_agent, policy_agent = three_agents origin, *everybody_else = testerchain.interface.w3.eth.accounts token_airdrop(token_agent, origin=testerchain.etherbase_account, addresses=everybody_else, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) miner = Miner(checksum_address=everybody_else[0], is_me=True) return miner
def staker(testerchain, agency): token_agent, staking_agent, policy_agent = agency origin, staker_account, *everybody_else = testerchain.client.accounts token_airdrop(token_agent=token_agent, origin=testerchain.etherbase_account, addresses=[staker_account], amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) staker = Staker(checksum_address=staker_account, is_me=True, blockchain=testerchain) return staker
def test_beneficiary_withdraws_tokens(testerchain, agent, agency, allocation_value, mock_transacting_power_activation, token_economics): token_agent, staking_agent, policy_agent = agency deployer_address, beneficiary_address, *everybody_else = testerchain.client.accounts contract_address = agent.contract_address assert token_agent.get_balance( address=contract_address ) == agent.unvested_tokens == agent.initial_locked_amount # Trying to withdraw the tokens now fails, obviously initial_amount = token_agent.get_balance(address=contract_address) with pytest.raises((TransactionFailed, ValueError)): agent.withdraw_tokens(value=initial_amount) # Let's deposit some of them (30% of initial amount) staked_amount = 3 * initial_amount // 10 mock_transacting_power_activation(account=agent.beneficiary, password=INSECURE_DEVELOPMENT_PASSWORD) _receipt = agent.deposit_as_staker( amount=staked_amount, lock_periods=token_economics.minimum_locked_periods) # Trying to withdraw the remaining fails too: # The locked amount is equal to the initial deposit (100% of the tokens). # Since 30% are staked, the locked amount is reduced by that 30% when withdrawing, # which results in an effective lock of 70%. However, the contract also has 70%, which means that, effectively, # the beneficiary can only withdraw 0 tokens. assert agent.available_balance == 0 with pytest.raises((TransactionFailed, ValueError)): agent.withdraw_tokens(value=initial_amount - staked_amount) agent.withdraw_tokens(value=0) # Now let's assume the contract has more tokens (e.g., coming from staking rewards). # The beneficiary should be able to collect this excess. mocked_rewards = NU.from_nunits(1000) token_airdrop(token_agent=token_agent, amount=mocked_rewards, origin=deployer_address, addresses=[contract_address]) assert agent.available_balance == mocked_rewards agent.withdraw_tokens(value=int(mocked_rewards)) # Once the lock passes, the beneficiary can withdraw what's left testerchain.time_travel(seconds=TEST_LOCK_DURATION_IN_SECONDS) receipt = agent.withdraw_tokens(value=initial_amount - staked_amount) assert receipt['status'] == 1, "Transaction Rejected" assert token_agent.get_balance(address=contract_address) == 0 assert token_agent.get_balance( address=beneficiary_address ) == initial_amount - staked_amount + mocked_rewards
def funded_blockchain(testerchain, agency, token_economics, test_registry): # Who are ya'? deployer_address, *everyone_else, staking_participant = testerchain.client.accounts # Free ETH!!! testerchain.ether_airdrop(amount=DEVELOPMENT_ETH_AIRDROP_AMOUNT) # Free Tokens!!! token_airdrop(token_agent=NucypherTokenAgent(registry=test_registry), origin=deployer_address, addresses=everyone_else, amount=token_economics.minimum_allowed_locked * 5) # HERE YOU GO yield testerchain, deployer_address
def stakers(testerchain, agency, token_economics): token_agent, _staking_agent, _policy_agent = agency blockchain = token_agent.blockchain # Mock Powerup consumption (Deployer) blockchain.transacting_power = TransactingPower( blockchain=blockchain, password=INSECURE_DEVELOPMENT_PASSWORD, account=blockchain.etherbase_account) blockchain.transacting_power.activate() token_airdrop(origin=blockchain.etherbase_account, addresses=blockchain.stakers_accounts, token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) stakers = list() for index, account in enumerate(blockchain.stakers_accounts): staker = Staker(is_me=True, checksum_address=account, blockchain=blockchain) # Mock TransactingPower consumption staker.blockchain.transacting_power = TransactingPower( blockchain=blockchain, password=INSECURE_DEVELOPMENT_PASSWORD, account=account) staker.blockchain.transacting_power.activate() min_stake, balance = token_economics.minimum_allowed_locked, staker.token_balance amount = random.randint(min_stake, balance) # for a random lock duration min_locktime, max_locktime = token_economics.minimum_locked_periods, token_economics.maximum_locked_periods periods = random.randint(min_locktime, max_locktime) staker.initialize_stake(amount=amount, lock_periods=periods) # We assume that the staker knows in advance the account of her worker worker_address = blockchain.ursula_account(index) staker.set_worker(worker_address=worker_address) stakers.append(staker) # Stake starts next period (or else signature validation will fail) blockchain.time_travel(periods=1) yield stakers
def funded_blockchain(deployed_blockchain): # Who are ya'? blockchain, _deployer_address, registry = deployed_blockchain deployer_address, *everyone_else, staking_participant = blockchain.interface.w3.eth.accounts # Free ETH!!! blockchain.ether_airdrop(amount=TESTING_ETH_AIRDROP_AMOUNT) # Free Tokens!!! token_airdrop(token_agent=NucypherTokenAgent(blockchain=blockchain), origin=_deployer_address, addresses=everyone_else, amount=MIN_ALLOWED_LOCKED * 5) # HERE YOU GO yield blockchain, _deployer_address
def funded_blockchain(deployed_blockchain, token_economics): # Who are ya'? blockchain, _deployer_address, registry = deployed_blockchain deployer_address, *everyone_else, staking_participant = blockchain.interface.w3.eth.accounts # Free ETH!!! blockchain.ether_airdrop(amount=DEVELOPMENT_ETH_AIRDROP_AMOUNT) # Free Tokens!!! token_airdrop(token_agent=NucypherTokenAgent(blockchain=blockchain), origin=_deployer_address, addresses=everyone_else, amount=token_economics.minimum_allowed_locked * 5) # HERE YOU GO yield blockchain, _deployer_address
def blockchain_ursulas(three_agents, ursula_decentralized_test_config): token_agent, miner_agent, policy_agent = three_agents etherbase, alice, bob, *all_yall = token_agent.blockchain.interface.w3.eth.accounts ursula_addresses = all_yall[:DEFAULT_NUMBER_OF_URSULAS_IN_DEVELOPMENT_NETWORK] token_airdrop(origin=etherbase, addresses=ursula_addresses, token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) _ursulas = make_decentralized_ursulas(ursula_config=ursula_decentralized_test_config, ether_addresses=ursula_addresses, stake=True) token_agent.blockchain.time_travel(periods=1) yield _ursulas
def idle_staker(testerchain, agency): token_agent, _staking_agent, _policy_agent = agency idle_staker_account = testerchain.unassigned_accounts[-2] # Mock Powerup consumption (Deployer) testerchain.transacting_power = TransactingPower(account=testerchain.etherbase_account) token_airdrop(origin=testerchain.etherbase_account, addresses=[idle_staker_account], token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) # Prepare idle staker idle_staker = Staker(is_me=True, checksum_address=idle_staker_account, blockchain=testerchain) yield idle_staker
def test_stake_in_idle_network(testerchain, token_economics, test_registry): # Let's fund a staker first token_agent = NucypherTokenAgent(registry=test_registry) token_airdrop(origin=testerchain.etherbase_account, addresses=testerchain.stakers_accounts, token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) account = testerchain.stakers_accounts[0] staker = Staker(is_me=True, checksum_address=account, registry=test_registry) # Mock TransactingPower consumption staker.transacting_power = TransactingPower(password=INSECURE_DEVELOPMENT_PASSWORD, account=staker.checksum_address) staker.transacting_power.activate() # Since StakingEscrow hasn't been activated yet, trying to deposit must fail amount = token_economics.minimum_allowed_locked periods = token_economics.minimum_locked_periods with pytest.raises((TransactionFailed, ValueError)): staker.initialize_stake(amount=amount, lock_periods=periods)
def simulate(config, action, nodes, federated_only, geth): """ Simulate the nucypher blockchain network Arguments ========== action - Which action to perform; The choices are: - start: Start a multi-process nucypher network simulation - stop: Stop a running simulation gracefully Options ======== --nodes - The quantity of nodes (processes) to execute during the simulation --duration = The number of periods to run the simulation before termination """ if action == 'start': # # Blockchain Connection # if not federated_only: if geth: test_provider_uri = "ipc:///tmp/geth.ipc" else: test_provider_uri = "pyevm://tester" simulation_registry = TemporaryEthereumContractRegistry() simulation_interface = BlockchainDeployerInterface(provider_uri=test_provider_uri, registry=simulation_registry, compiler=SolidityCompiler()) blockchain = TesterBlockchain(interface=simulation_interface, test_accounts=nodes, airdrop=False) accounts = blockchain.interface.w3.eth.accounts origin, *everyone_else = accounts # Set the deployer address from the freshly created test account simulation_interface.deployer_address = origin # # Blockchain Action # blockchain.ether_airdrop(amount=DEVELOPMENT_ETH_AIRDROP_AMOUNT) click.confirm("Deploy all nucypher contracts to {}?".format(test_provider_uri), abort=True) click.echo("Bootstrapping simulated blockchain network") # Deploy contracts token_deployer = NucypherTokenDeployer(blockchain=blockchain, deployer_address=origin) token_deployer.arm() token_deployer.deploy() token_agent = token_deployer.make_agent() miners_escrow_secret = os.urandom(DISPATCHER_SECRET_LENGTH) miner_escrow_deployer = MinerEscrowDeployer(token_agent=token_agent, deployer_address=origin, secret_hash=miners_escrow_secret) miner_escrow_deployer.arm() miner_escrow_deployer.deploy() miner_agent = miner_escrow_deployer.make_agent() policy_manager_secret = os.urandom(DISPATCHER_SECRET_LENGTH) policy_manager_deployer = PolicyManagerDeployer(miner_agent=miner_agent, deployer_address=origin, secret_hash=policy_manager_secret) policy_manager_deployer.arm() policy_manager_deployer.deploy() policy_agent = policy_manager_deployer.make_agent() airdrop_amount = DEVELOPMENT_TOKEN_AIRDROP_AMOUNT click.echo("Airdropping tokens {} to {} addresses".format(airdrop_amount, len(everyone_else))) _receipts = token_airdrop(token_agent=token_agent, origin=origin, addresses=everyone_else, amount=airdrop_amount) # Commit the current state of deployment to a registry file. click.echo("Writing filesystem registry") _sim_registry_name = blockchain.interface.registry.commit(filepath=DEFAULT_SIMULATION_REGISTRY_FILEPATH) click.echo("Ready to run swarm.") # # Swarm # # Select a port range to use on localhost for sim servers if not federated_only: sim_addresses = everyone_else else: sim_addresses = NotImplemented start_port = 8787 counter = 0 for sim_port_number, sim_address in enumerate(sim_addresses, start=start_port): # # Parse ursula parameters # rest_port = sim_port_number db_name = 'sim-{}'.format(rest_port) cli_exec = os.path.join(BASE_DIR, 'cli', 'main.py') python_exec = 'python' proc_params = ''' python3 {} run_ursula --rest-port {} --db-name {} '''.format(python_exec, cli_exec, rest_port, db_name).split() if federated_only: proc_params.append('--federated-only') else: token_agent = NucypherTokenAgent(blockchain=blockchain) miner_agent = MinerAgent(token_agent=token_agent) miner = Miner(miner_agent=miner_agent, checksum_address=sim_address) # stake a random amount min_stake, balance = MIN_ALLOWED_LOCKED, miner.token_balance value = random.randint(min_stake, balance) # for a random lock duration min_locktime, max_locktime = MIN_LOCKED_PERIODS, MAX_MINTING_PERIODS periods = random.randint(min_locktime, max_locktime) miner.initialize_stake(amount=value, lock_periods=periods) click.echo("{} Initialized new stake: {} tokens for {} periods".format(sim_address, value, periods)) proc_params.extend('--checksum-address {}'.format(sim_address).split()) # Spawn click.echo("Spawning node #{}".format(counter+1)) processProtocol = UrsulaProcessProtocol(command=proc_params) cli_exec = os.path.join(BASE_DIR, 'cli', 'main.py') ursula_proc = reactor.spawnProcess(processProtocol, cli_exec, proc_params) # # post-spawnProcess # # Start with some basic status data, then build on it rest_uri = "http://{}:{}".format('localhost', rest_port) sim_data = "Started simulated Ursula | ReST {}".format(rest_uri) rest_uri = "{host}:{port}".format(host='localhost', port=str(sim_port_number)) sim_data.format(rest_uri) # if not federated_only: # stake_infos = tuple(config.miner_agent.get_all_stakes(miner_address=sim_address)) # sim_data += '| ETH address {}'.format(sim_address) # sim_data += '| {} Active stakes '.format(len(stake_infos)) click.echo(sim_data) counter += 1 click.echo("Starting the reactor") click.confirm("Start the reactor?", abort=True) try: reactor.run() finally: if not federated_only: click.echo("Removing simulation registry") os.remove(DEFAULT_SIMULATION_REGISTRY_FILEPATH) click.echo("Stopping simulated Ursula processes") for process in config.sim_processes: os.kill(process.pid, 9) click.echo("Killed {}".format(process)) click.echo("Simulation completed") elif action == 'stop': # Kill the simulated ursulas for process in config.ursula_processes: process.transport.signalProcess('KILL') elif action == 'status': if not config.simulation_running: status_message = "Simulation not running." else: ursula_processes = len(config.ursula_processes) status_message = """ | Node Swarm Simulation Status | Simulation processes .............. {} """.format(ursula_processes) click.echo(status_message) elif action == 'demo': """Run the finnegans wake demo""" demo_exec = os.path.join(BASE_DIR, 'cli', 'demos', 'finnegans-wake-demo.py') process_args = [sys.executable, demo_exec] if federated_only: process_args.append('--federated-only') subprocess.run(process_args, stdout=subprocess.PIPE)