mirror of https://github.com/nucypher/nucypher.git
Respond to RFCs in PR #1064 - Staker to/from blockchain, @michwill's funding account recipt fix; Touch Ups.
parent
f7d780639d
commit
362aff4824
|
@ -381,6 +381,22 @@ class Staker(NucypherTokenActor):
|
||||||
self.staking_agent = StakingEscrowAgent(blockchain=self.blockchain)
|
self.staking_agent = StakingEscrowAgent(blockchain=self.blockchain)
|
||||||
self.economics = economics or TokenEconomics()
|
self.economics = economics or TokenEconomics()
|
||||||
self.is_me = is_me
|
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
|
@property
|
||||||
def stakes(self) -> List[Stake]:
|
def stakes(self) -> List[Stake]:
|
||||||
|
@ -489,16 +505,21 @@ class Staker(NucypherTokenActor):
|
||||||
@save_receipt
|
@save_receipt
|
||||||
def set_worker(self, worker_address: str) -> str:
|
def set_worker(self, worker_address: str) -> str:
|
||||||
# TODO: Set a Worker for this staker, not just in StakingEscrow
|
# TODO: Set a Worker for this staker, not just in StakingEscrow
|
||||||
receipt = self.staking_agent.set_worker(staker_address=self.checksum_address,
|
receipt = self.staking_agent.set_worker(staker_address=self.checksum_address, worker_address=worker_address)
|
||||||
worker_address=worker_address)
|
self.__worker_address = worker_address
|
||||||
return receipt
|
return receipt
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def worker_address(self) -> str:
|
def worker_address(self) -> str:
|
||||||
worker_address = self.staking_agent.get_worker_from_staker(staker_address=self.checksum_address)
|
if self.__worker_address:
|
||||||
if worker_address is BlockchainInterface.NULL_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 NO_WORKER_ASSIGNED
|
||||||
return worker_address
|
return self.__worker_address
|
||||||
|
|
||||||
@only_me
|
@only_me
|
||||||
@save_receipt
|
@save_receipt
|
||||||
|
@ -746,7 +767,7 @@ class StakeHolder(BaseConfiguration):
|
||||||
blockchain=self.blockchain.to_dict(),
|
blockchain=self.blockchain.to_dict(),
|
||||||
funding_account=self.funding_account,
|
funding_account=self.funding_account,
|
||||||
accounts=self.__accounts,
|
accounts=self.__accounts,
|
||||||
stakers=self.__serialize_stake_info())
|
stakers=self.__serialize_stakers())
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -861,20 +882,13 @@ class StakeHolder(BaseConfiguration):
|
||||||
balances = dict()
|
balances = dict()
|
||||||
for staker in self.stakers:
|
for staker in self.stakers:
|
||||||
staker_funds = {'ETH': staker.eth_balance, 'NU': staker.token_balance}
|
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
|
return balances
|
||||||
|
|
||||||
def __serialize_stake_info(self) -> list:
|
def __serialize_stakers(self) -> list:
|
||||||
payload = list()
|
payload = list()
|
||||||
for staker in self.stakers:
|
for staker in self.stakers:
|
||||||
stake_info = [stake.to_stake_info() for stake in staker.stakes]
|
payload.append(staker.to_dict())
|
||||||
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)
|
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
def get_active_staker(self, address: str) -> Staker:
|
def get_active_staker(self, address: str) -> Staker:
|
||||||
|
@ -887,7 +901,7 @@ class StakeHolder(BaseConfiguration):
|
||||||
|
|
||||||
def __create_staker(self, password: str = None) -> Staker:
|
def __create_staker(self, password: str = None) -> Staker:
|
||||||
"""Create a new account and return it as a Staker instance."""
|
"""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?
|
# TODO: More formal check for wallet here?
|
||||||
# With devices, the last account is is always an unsed one.
|
# With devices, the last account is is always an unsed one.
|
||||||
new_account = self.blockchain.client.accounts[-1]
|
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."""
|
"""Creates a new ethereum account, then transfers it ETH and NU for staking."""
|
||||||
if self.funding_tokens < amount:
|
if self.funding_tokens < amount:
|
||||||
delta = amount - staker.token_balance
|
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:
|
if not self.funding_eth:
|
||||||
raise self.ConfigurationError(f"{self.funding_account} has no ETH")
|
raise self.ConfigurationError(f"{self.funding_account} has no ETH")
|
||||||
|
|
||||||
|
@ -935,10 +950,9 @@ class StakeHolder(BaseConfiguration):
|
||||||
self.funding_power.activate()
|
self.funding_power.activate()
|
||||||
|
|
||||||
# Send new staker account ETH
|
# Send new staker account ETH
|
||||||
tx = {'to': staker.checksum_address,
|
tx = {'to': staker.checksum_address, 'from': self.funding_account, 'value': self.eth_funding}
|
||||||
'from': self.funding_account,
|
txhash = self.blockchain.client.send_transaction(transaction=tx)
|
||||||
'value': self.eth_funding}
|
_ether_transfer_receipt = self.blockchain.client.wait_for_receipt(txhash, timeout=120) # TODO: Include in config?
|
||||||
_ether_transfer_receipt = self.blockchain.client.send_transaction(transaction=tx)
|
|
||||||
|
|
||||||
# Send new staker account NU
|
# Send new staker account NU
|
||||||
_result = self.token_agent.transfer(amount=amount.to_nunits(),
|
_result = self.token_agent.transfer(amount=amount.to_nunits(),
|
||||||
|
|
|
@ -126,7 +126,7 @@ class NucypherTokenAgent(EthereumContractAgent, metaclass=Agency):
|
||||||
|
|
||||||
def increase_allowance(self, sender_address: str, target_address: str, increase: int):
|
def increase_allowance(self, sender_address: str, target_address: str, increase: int):
|
||||||
contract_function = self.contract.functions.increaseAllowance(target_address, increase)
|
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)
|
sender_address=sender_address)
|
||||||
return receipt
|
return receipt
|
||||||
|
|
||||||
|
|
|
@ -273,8 +273,6 @@ class GethClient(Web3Client):
|
||||||
return self.w3.geth.admin.peers()
|
return self.w3.geth.admin.peers()
|
||||||
|
|
||||||
def unlock_account(self, address, password):
|
def unlock_account(self, address, password):
|
||||||
# if self.is_local:
|
|
||||||
# return True
|
|
||||||
return self.w3.geth.personal.unlockAccount(address, password)
|
return self.w3.geth.personal.unlockAccount(address, password)
|
||||||
|
|
||||||
def sign_transaction(self, transaction: dict) -> bytes:
|
def sign_transaction(self, transaction: dict) -> bytes:
|
||||||
|
@ -329,7 +327,8 @@ class EthereumTesterClient(Web3Client):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def new_account(self, password: str):
|
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
|
return insecure_account
|
||||||
|
|
||||||
def sign_transaction(self, transaction: dict):
|
def sign_transaction(self, transaction: dict):
|
||||||
|
|
|
@ -318,7 +318,7 @@ class BlockchainInterface:
|
||||||
payload.update({'chainId': int(self.client.chain_id),
|
payload.update({'chainId': int(self.client.chain_id),
|
||||||
'nonce': nonce,
|
'nonce': nonce,
|
||||||
'from': sender_address,
|
'from': sender_address,
|
||||||
'gasPrice': self.client.w3.eth.gasPrice,
|
'gasPrice': self.client.gas_price,
|
||||||
# 'gas': 0, # TODO: Gas Management
|
# 'gas': 0, # TODO: Gas Management
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,6 @@ def test_software_stakeholder_configuration(testerchain,
|
||||||
|
|
||||||
# Check attributes can be successfully read
|
# Check attributes can be successfully read
|
||||||
assert stakeholder.total_stake
|
assert stakeholder.total_stake
|
||||||
assert stakeholder.trezor is False
|
|
||||||
assert stakeholder.stakes
|
assert stakeholder.stakes
|
||||||
assert stakeholder.accounts
|
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):
|
def test_divide_stake(staking_software_stakeholder, token_economics):
|
||||||
stake = staking_software_stakeholder.stakes[1]
|
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,
|
original_stake, new_stake = staking_software_stakeholder.divide_stake(address=stake.owner_address,
|
||||||
password=INSECURE_DEVELOPMENT_PASSWORD,
|
password=INSECURE_DEVELOPMENT_PASSWORD,
|
||||||
index=0,
|
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))
|
stakes = list(staking_agent.get_all_stakes(staker_address=stake.owner_address))
|
||||||
assert len(stakes) == 2
|
assert len(stakes) == 2
|
||||||
assert new_stake.value == target_value
|
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):
|
def test_set_worker(staking_software_stakeholder, manual_worker):
|
||||||
|
|
Loading…
Reference in New Issue