Removes minerIds and datastore

pull/330/head
szotov 2018-06-14 13:55:46 -07:00 committed by Kieran Prasch
parent e4253b6c5d
commit 2999110c16
8 changed files with 87 additions and 152 deletions

View File

@ -86,11 +86,6 @@ class Miner(NucypherTokenActor):
# Establish initial state
self.is_me = is_me
if self.ether_address is not constants.UNKNOWN_ACTOR:
node_datastore = self.miner_agent._fetch_node_datastore(node_address=self.ether_address)
else:
node_datastore = constants.CONTRACT_DATASTORE_UNAVAILIBLE
self.__node_datastore = node_datastore
@classmethod
def from_config(cls, blockchain_config) -> 'Miner':
@ -211,11 +206,9 @@ class Miner(NucypherTokenActor):
if entire_balance is True:
amount = self.token_balance
amount, lock_periods = int(amount), int(lock_periods) # Manual type checks below this point in the stack;
staking_transactions = OrderedDict() # Time series of txhases
# Validate
amount = self.blockchain.interface.w3.toInt(amount)
assert self.__validate_stake(amount=amount, lock_periods=lock_periods)
# Transact

View File

@ -85,13 +85,6 @@ class MinerAgent(EthereumContractAgent):
class NotEnoughMiners(Exception):
pass
class MinerInfo(Enum):
VALUE = 0
DECIMALS = 1
LAST_ACTIVE_PERIOD = 2
CONFIRMED_PERIOD_1 = 3
CONFIRMED_PERIOD_2 = 4
def __init__(self, token_agent: NucypherTokenAgent=None, *args, **kwargs):
token_agent = token_agent if token_agent is not None else NucypherTokenAgent()
super().__init__(blockchain=token_agent.blockchain, *args, **kwargs)
@ -154,7 +147,7 @@ class MinerAgent(EthereumContractAgent):
return txhash
def mint(self, node_address) -> Tuple[str, str]:
"""Computes and transfers tokens to the miner's account"""
"""Computes reward tokens for the miner's account"""
mint_txhash = self.contract.functions.mint().transact({'from': node_address})
self.blockchain.wait_for_receipt(mint_txhash)
@ -173,55 +166,20 @@ class MinerAgent(EthereumContractAgent):
return collection_txhash
# Node Datastore #
def _publish_datastore(self, node_address: str, data) -> str:
"""Publish new data to the MinerEscrow contract as a public record associated with this miner."""
txhash = self.contract.functions.setMinerId(data).transact({'from': node_address})
self.blockchain.wait_for_receipt(txhash)
return txhash
def _get_datastore_entries(self, node_address: str) -> int:
count_bytes = self.contract.functions.getMinerIdsLength(node_address).call()
datastore_entries = self.blockchain.interface.w3.toInt(count_bytes)
return datastore_entries
def _fetch_node_datastore(self, node_address):
"""Cache a generator of all asosciated contract data for this miner."""
datastore_entries = self._get_datastore_entries(node_address=node_address)
def __node_datastore_reader():
for index in range(datastore_entries):
value = self.contract.functions.getMinerId(node_address, index).call()
yield value
return __node_datastore_reader()
#
# Contract Utilities
#
def swarm(self, fetch_data: bool=False) -> Union[Generator[str, None, None], Generator[Tuple[str, bytes], None, None]]:
def swarm(self) -> Union[Generator[str, None, None], Generator[Tuple[str, bytes], None, None]]:
"""
Returns an iterator of all miner addresses via cumulative sum, on-network.
if fetch_data is true, tuples containing the address and the miners stored data are yielded.
Miner addresses are returned in the order in which they registered with the MinersEscrow contract's ledger
"""
for index in range(self.get_miner_population()):
miner_address = self.contract.functions.miners(index).call()
validated_address = self.blockchain.interface.w3.toChecksumAddress(miner_address) # string address of next node
if fetch_data is True:
stored_miner_data = self.contract.functions.getMinerIdsLength(miner_address).call()
yield (validated_address, stored_miner_data)
else:
yield validated_address
yield miner_address
def sample(self, quantity: int, duration: int, additional_ursulas: float=1.7, attempts: int=5) -> List[str]:
"""

View File

@ -111,7 +111,7 @@ def datetime_to_period(datetime: maya.MayaDT) -> int:
"""Converts a MayaDT instance to a period number."""
future_period = datetime._epoch // int(SECONDS_PER_PERIOD)
return future_period
return int(future_period)
def calculate_period_duration(future_time: maya.MayaDT) -> int:

View File

@ -64,7 +64,6 @@ contract MinersEscrow is Issuer {
uint256 lastActivePeriod;
Downtime[] downtime;
StakeInfo[] stakes;
bytes[] minerIds;
}
/*
@ -628,28 +627,6 @@ contract MinersEscrow is Issuer {
policyManager = _policyManager;
}
/**
* @notice Return the length of the miner ids array
**/
function getMinerIdsLength(address _miner) public view returns (uint256) {
return minerInfo[_miner].minerIds.length;
}
/**
* @notice Return the miner id
**/
function getMinerId(address _miner, uint256 _index) public view returns (bytes) {
return minerInfo[_miner].minerIds[_index];
}
/**
* @notice Set the miner id
**/
function setMinerId(bytes _minerId) public {
MinerInfo storage info = minerInfo[msg.sender];
info.minerIds.push(_minerId);
}
/**
* @notice Return the length of the miners array
**/
@ -737,18 +714,6 @@ contract MinersEscrow is Issuer {
}
}
/**
* @dev Get miner id bytes by delegatecall
**/
function delegateGetMinerId(address _target, string _signature, address _miner, uint256 _index)
internal returns (bytes memory result)
{
bytes32 memoryAddress = delegateGetData(_target, _signature, 2, bytes32(_miner), bytes32(_index));
assembly {
result := add(memoryAddress, mload(memoryAddress))
}
}
function verifyState(address _testTarget) public onlyOwner {
super.verifyState(_testTarget);
require(uint256(delegateGet(_testTarget, "minLockedPeriods()")) ==
@ -792,16 +757,6 @@ contract MinersEscrow is Issuer {
stakeInfoToCheck.periods == stakeInfo.periods &&
stakeInfoToCheck.lockedValue == stakeInfo.lockedValue);
}
require(uint256(delegateGet(_testTarget, "getMinerIdsLength(address)", miner)) == info.minerIds.length);
for (i = 0; i < info.minerIds.length && i < MAX_CHECKED_VALUES; i++) {
// TODO try to optimize size
bytes memory minerIdToCheck =
delegateGetMinerId(_testTarget, "getMinerId(address,uint256)", minerAddress, i);
bytes storage minerId = info.minerIds[i];
require(minerIdToCheck.length == minerId.length &&
keccak256(minerIdToCheck) == keccak256(minerId));
}
}
function finishUpgrade(address _target) public onlyOwner {

View File

@ -894,38 +894,6 @@ def test_pre_deposit(testerchain, token, escrow_contract):
assert 250 == event_args['periods']
@pytest.mark.slow
def test_miner_id(testerchain, token, escrow_contract):
escrow = escrow_contract(5 * 10 ** 8)
creator = testerchain.interface.w3.eth.accounts[0]
miner = testerchain.interface.w3.eth.accounts[1]
# Initialize contract and miner
tx = escrow.functions.initialize().transact({'from': creator})
testerchain.wait_for_receipt(tx)
tx = token.functions.transfer(miner, 1000).transact({'from': creator})
testerchain.wait_for_receipt(tx)
balance = token.functions.balanceOf(miner).call()
tx = token.functions.approve(escrow.address, balance).transact({'from': miner})
testerchain.wait_for_receipt(tx)
tx = escrow.functions.deposit(balance, 2).transact({'from': miner})
testerchain.wait_for_receipt(tx)
# Set miner ids
miner_id = os.urandom(33)
tx = escrow.functions.setMinerId(miner_id).transact({'from': miner})
testerchain.wait_for_receipt(tx)
assert 1 == escrow.functions.getMinerIdsLength(miner).call()
assert miner_id == escrow.functions.getMinerId(miner, 0).call()
miner_id = os.urandom(66)
tx = escrow.functions.setMinerId(miner_id).transact({'from': miner})
testerchain.wait_for_receipt(tx)
assert 2 == escrow.functions.getMinerIdsLength(miner).call()
assert miner_id == escrow.functions.getMinerId(miner, 1).call()
@pytest.mark.slow
def test_verifying_state(testerchain, token):
creator = testerchain.interface.w3.eth.accounts[0]
@ -963,9 +931,6 @@ def test_verifying_state(testerchain, token):
tx = token.functions.approve(contract.address, balance).transact({'from': miner})
testerchain.wait_for_receipt(tx)
tx = contract.functions.deposit(balance, 1000).transact({'from': miner})
testerchain.wait_for_receipt(tx)
tx = contract.functions.setMinerId(testerchain.interface.w3.toBytes(111)).transact({'from': miner})
testerchain.wait_for_receipt(tx)
# Upgrade to the second version
@ -976,8 +941,6 @@ def test_verifying_state(testerchain, token):
assert 1500 == contract.functions.maxAllowableLockedTokens().call()
assert policy_manager.address == contract.functions.policyManager().call()
assert 2 == contract.functions.valueToCheck().call()
assert 1 == testerchain.interface.w3.toInt(contract.functions.getMinerIdsLength(miner).call())
assert 111 == testerchain.interface.w3.toInt(contract.functions.getMinerId(miner, 0).call())
tx = contract.functions.setValueToCheck(3).transact({'from': creator})
testerchain.wait_for_receipt(tx)
assert 3 == contract.functions.valueToCheck().call()

View File

@ -21,26 +21,23 @@ class TestMiner:
def test_miner_locking_tokens(self, testerchain, miner, mock_miner_agent):
testerchain.ether_airdrop(amount=10000)
assert constants.MIN_ALLOWED_LOCKED < miner.token_balance, "Insufficient miner balance"
now = maya.now()
expiration = now.add(days=constants.MIN_LOCKED_PERIODS)
miner.stake(amount=constants.MIN_ALLOWED_LOCKED, # Lock the minimum amount of tokens
expiration = maya.now().add(days=constants.MIN_LOCKED_PERIODS)
miner.stake(amount=int(constants.MIN_ALLOWED_LOCKED), # Lock the minimum amount of tokens
expiration=expiration)
# lock_periods=constants.MIN_LOCKED_PERIODS) # ... for the fewest number of periods
# Verify that the escrow is "approved" to receive tokens
assert mock_miner_agent.token_agent.contract.functions.allowance(miner.ether_address,
mock_miner_agent.contract_address).call() == 0
allowance = mock_miner_agent.token_agent.contract.functions.allowance(
miner.ether_address,
mock_miner_agent.contract_address).call()
assert 0 == allowance
# Staking starts after one period
assert mock_miner_agent.contract.functions.getLockedTokens(miner.ether_address).call() == 0
# Wait for it...
testerchain.time_travel(periods=1)
assert mock_miner_agent.contract.functions.getLockedTokens(miner.ether_address).call() == constants.MIN_ALLOWED_LOCKED
locked_tokens = mock_miner_agent.contract.functions.getLockedTokens(miner.ether_address).call()
assert 0 == locked_tokens
locked_tokens = mock_miner_agent.contract.functions.getLockedTokens(miner.ether_address, 1).call()
assert constants.MIN_ALLOWED_LOCKED == locked_tokens
@pytest.mark.usefixtures("mock_policy_agent")
def test_miner_divides_stake(self, miner):
@ -78,10 +75,10 @@ class TestMiner:
# Capture the current token balance of the miner
initial_balance = miner.token_balance
assert mock_token_agent.get_balance(miner.ether_address) == miner.token_balance
assert mock_token_agent.get_balance(miner.ether_address) == initial_balance
miner.stake(amount=constants.MIN_ALLOWED_LOCKED, # Lock the minimum amount of tokens
lock_periods=constants.MIN_LOCKED_PERIODS) # ... for the fewest number of periods
miner.stake(amount=int(constants.MIN_ALLOWED_LOCKED), # Lock the minimum amount of tokens
lock_periods=int(constants.MIN_LOCKED_PERIODS)) # ... for the fewest number of periods
# Have other address lock tokens
_origin, ursula, *everybody_else = deployed_testerchain.interface.w3.eth.accounts

View File

@ -31,8 +31,9 @@ def test_get_swarm(mock_miner_agent):
@pytest.mark.usefixtures("miners")
def test_sample_miners(mock_miner_agent):
miners_population = mock_miner_agent.get_miner_population()
with pytest.raises(MinerAgent.NotEnoughMiners):
mock_miner_agent.sample(quantity=100) # Waay more than we have deployed
mock_miner_agent.sample(quantity=miners_population + 1) # Way more than we have deployed
miners = mock_miner_agent.sample(quantity=3)
assert len(miners) == 3 # Three..

View File

@ -0,0 +1,68 @@
import pytest
from nucypher.blockchain.eth.agents import NucypherTokenAgent, MinerAgent
from nucypher.blockchain.eth.deployers import NucypherTokenDeployer, MinerEscrowDeployer, PolicyManagerDeployer
from nucypher.blockchain.eth.interfaces import EthereumContractRegistrar
def test_token_deployer_and_agent(testerchain):
origin, *everybody_else = testerchain.interface.w3.eth.accounts
# Trying to get token from blockchain before it's been published fails
with pytest.raises(EthereumContractRegistrar.UnknownContract):
NucypherTokenAgent(blockchain=testerchain)
# The big day...
deployer = NucypherTokenDeployer(blockchain=testerchain, deployer_address=origin)
# It's not armed
with pytest.raises(NucypherTokenDeployer.ContractDeploymentError):
deployer.deploy()
# Token must be armed before deploying to the blockchain
deployer.arm()
deployer.deploy()
# Create a token instance
token_agent = deployer.make_agent()
token_contract = testerchain.get_contract(token_agent.contract_address)
expected_token_supply = token_contract.functions.totalSupply().call()
assert expected_token_supply == token_agent.contract.functions.totalSupply().call()
# Retrieve the token from the blockchain
same_token_agent = NucypherTokenAgent(blockchain=testerchain)
# Compare the contract address for equality
assert token_agent.contract_address == same_token_agent.contract_address
assert token_agent == same_token_agent # __eq__
@pytest.mark.slow()
def test_deploy_ethereum_contracts(testerchain):
"""
Launch all ethereum contracts:
- NuCypherToken
- PolicyManager
- MinersEscrow
- UserEscrow
- Issuer
"""
origin, *everybody_else = testerchain.interface.w3.eth.accounts
token_deployer = NucypherTokenDeployer(blockchain=testerchain, deployer_address=origin)
token_deployer.arm()
token_deployer.deploy()
token_agent = NucypherTokenAgent(blockchain=testerchain)
miner_escrow_deployer = MinerEscrowDeployer(token_agent=token_agent, deployer_address=origin)
miner_escrow_deployer.arm()
miner_escrow_deployer.deploy()
miner_agent = MinerAgent(token_agent=token_agent)
policy_manager_contract = PolicyManagerDeployer(miner_agent=miner_agent, deployer_address=origin)
policy_manager_contract.arm()
policy_manager_contract.deploy()
# TODO: Assert