diff --git a/nucypher/blockchain/eth/actors.py b/nucypher/blockchain/eth/actors.py index 83ac84d75..cd913533d 100644 --- a/nucypher/blockchain/eth/actors.py +++ b/nucypher/blockchain/eth/actors.py @@ -381,6 +381,22 @@ class Staker(NucypherTokenActor): self.staking_agent = StakingEscrowAgent(blockchain=self.blockchain) self.economics = economics or TokenEconomics() self.is_me = is_me + self.__worker_address = None + + def to_dict(self) -> dict: + stake_info = [stake.to_stake_info() for stake in self.stakes] + worker_address = self.worker_address or NO_WORKER_ASSIGNED + staker_funds = {'ETH': int(self.eth_balance), 'NU': int(self.token_balance)} + staker_payload = {'staker': self.checksum_address, + 'balances': staker_funds, + 'worker': worker_address, + 'stakes': stake_info} + return staker_payload + + @classmethod + def from_dict(cls, staker_payload: dict) -> 'Staker': + staker = Staker(is_me=True, checksum_address=staker_payload['checksum_address']) + return staker @property def stakes(self) -> List[Stake]: @@ -489,16 +505,21 @@ class Staker(NucypherTokenActor): @save_receipt def set_worker(self, worker_address: str) -> str: # TODO: Set a Worker for this staker, not just in StakingEscrow - receipt = self.staking_agent.set_worker(staker_address=self.checksum_address, - worker_address=worker_address) + receipt = self.staking_agent.set_worker(staker_address=self.checksum_address, worker_address=worker_address) + self.__worker_address = worker_address return receipt @property def worker_address(self) -> str: - worker_address = self.staking_agent.get_worker_from_staker(staker_address=self.checksum_address) - if worker_address is BlockchainInterface.NULL_ADDRESS: + if self.__worker_address: + return self.__worker_address + else: + worker_address = self.staking_agent.get_worker_from_staker(staker_address=self.checksum_address) + self.__worker_address = worker_address + + if self.__worker_address == BlockchainInterface.NULL_ADDRESS: return NO_WORKER_ASSIGNED - return worker_address + return self.__worker_address @only_me @save_receipt @@ -746,7 +767,7 @@ class StakeHolder(BaseConfiguration): blockchain=self.blockchain.to_dict(), funding_account=self.funding_account, accounts=self.__accounts, - stakers=self.__serialize_stake_info()) + stakers=self.__serialize_stakers()) return payload @classmethod @@ -861,20 +882,13 @@ class StakeHolder(BaseConfiguration): balances = dict() for staker in self.stakers: staker_funds = {'ETH': staker.eth_balance, 'NU': staker.token_balance} - balances = {staker.checksum_address: staker_funds} + balances[staker.checksum_address] = {staker.checksum_address: staker_funds} return balances - def __serialize_stake_info(self) -> list: + def __serialize_stakers(self) -> list: payload = list() for staker in self.stakers: - stake_info = [stake.to_stake_info() for stake in staker.stakes] - worker_address = staker.worker_address or NO_WORKER_ASSIGNED - staker_funds = {'ETH': int(staker.eth_balance), 'NU': int(staker.token_balance)} - staker_payload = {'staker': staker.checksum_address, - 'balances': staker_funds, - 'worker': worker_address, - 'stakes': stake_info} - payload.append(staker_payload) + payload.append(staker.to_dict()) return payload def get_active_staker(self, address: str) -> Staker: @@ -887,7 +901,7 @@ class StakeHolder(BaseConfiguration): def __create_staker(self, password: str = None) -> Staker: """Create a new account and return it as a Staker instance.""" - if self.device: + if self.funding_power.device: # TODO: More formal check for wallet here? # With devices, the last account is is always an unsed one. new_account = self.blockchain.client.accounts[-1] @@ -927,7 +941,8 @@ class StakeHolder(BaseConfiguration): """Creates a new ethereum account, then transfers it ETH and NU for staking.""" if self.funding_tokens < amount: delta = amount - staker.token_balance - raise self.ConfigurationError(f"{self.funding_account} Insufficient NU (need {delta} more).") + message = f"{self.funding_account} Insufficient NU (need {delta} more to transfer a total of {amount})." + raise self.ConfigurationError(message) if not self.funding_eth: raise self.ConfigurationError(f"{self.funding_account} has no ETH") @@ -935,10 +950,9 @@ class StakeHolder(BaseConfiguration): self.funding_power.activate() # Send new staker account ETH - tx = {'to': staker.checksum_address, - 'from': self.funding_account, - 'value': self.eth_funding} - _ether_transfer_receipt = self.blockchain.client.send_transaction(transaction=tx) + tx = {'to': staker.checksum_address, 'from': self.funding_account, 'value': self.eth_funding} + txhash = self.blockchain.client.send_transaction(transaction=tx) + _ether_transfer_receipt = self.blockchain.client.wait_for_receipt(txhash, timeout=120) # TODO: Include in config? # Send new staker account NU _result = self.token_agent.transfer(amount=amount.to_nunits(), diff --git a/nucypher/blockchain/eth/agents.py b/nucypher/blockchain/eth/agents.py index 5de84bc58..36393f367 100644 --- a/nucypher/blockchain/eth/agents.py +++ b/nucypher/blockchain/eth/agents.py @@ -126,7 +126,7 @@ class NucypherTokenAgent(EthereumContractAgent, metaclass=Agency): def increase_allowance(self, sender_address: str, target_address: str, increase: int): contract_function = self.contract.functions.increaseAllowance(target_address, increase) - receipt = self.blockchain.send_transaction(transaction_function=contract_function, + receipt = self.blockchain.send_transaction(contract_function=contract_function, sender_address=sender_address) return receipt diff --git a/nucypher/blockchain/eth/clients.py b/nucypher/blockchain/eth/clients.py index 7f26cee37..ff636009c 100644 --- a/nucypher/blockchain/eth/clients.py +++ b/nucypher/blockchain/eth/clients.py @@ -273,8 +273,6 @@ class GethClient(Web3Client): return self.w3.geth.admin.peers() def unlock_account(self, address, password): - # if self.is_local: - # return True return self.w3.geth.personal.unlockAccount(address, password) def sign_transaction(self, transaction: dict) -> bytes: @@ -329,7 +327,8 @@ class EthereumTesterClient(Web3Client): return True def new_account(self, password: str): - insecure_account = self.w3.provider.ethereum_tester.add_account(os.urandom(32).hex(), password=password) + insecure_account = self.w3.provider.ethereum_tester.add_account(private_key=os.urandom(32).hex(), + password=password) return insecure_account def sign_transaction(self, transaction: dict): diff --git a/nucypher/blockchain/eth/interfaces.py b/nucypher/blockchain/eth/interfaces.py index f8c6b3c59..d6584f58e 100644 --- a/nucypher/blockchain/eth/interfaces.py +++ b/nucypher/blockchain/eth/interfaces.py @@ -318,7 +318,7 @@ class BlockchainInterface: payload.update({'chainId': int(self.client.chain_id), 'nonce': nonce, 'from': sender_address, - 'gasPrice': self.client.w3.eth.gasPrice, + 'gasPrice': self.client.gas_price, # 'gas': 0, # TODO: Gas Management }) diff --git a/tests/blockchain/eth/entities/actors/test_stakeholder.py b/tests/blockchain/eth/entities/actors/test_stakeholder.py index ad9f639df..455c425bf 100644 --- a/tests/blockchain/eth/entities/actors/test_stakeholder.py +++ b/tests/blockchain/eth/entities/actors/test_stakeholder.py @@ -92,7 +92,6 @@ def test_software_stakeholder_configuration(testerchain, # Check attributes can be successfully read assert stakeholder.total_stake - assert stakeholder.trezor is False assert stakeholder.stakes assert stakeholder.accounts @@ -162,7 +161,9 @@ def test_initialize_stake_with_new_account(staking_software_stakeholder, stake_v def test_divide_stake(staking_software_stakeholder, token_economics): stake = staking_software_stakeholder.stakes[1] - target_value = token_economics.minimum_allowed_locked * 2 + target_value = token_economics.minimum_allowed_locked + pre_divide_stake_value = stake.value + original_stake, new_stake = staking_software_stakeholder.divide_stake(address=stake.owner_address, password=INSECURE_DEVELOPMENT_PASSWORD, index=0, @@ -173,6 +174,7 @@ def test_divide_stake(staking_software_stakeholder, token_economics): stakes = list(staking_agent.get_all_stakes(staker_address=stake.owner_address)) assert len(stakes) == 2 assert new_stake.value == target_value + assert original_stake.value == (pre_divide_stake_value - target_value) def test_set_worker(staking_software_stakeholder, manual_worker):