Apply suggestions from code review #1459

Co-Authored-By: Derek Pierre <derek.pierre@gmail.com>
Co-Authored-By: David Núñez <david@nucypher.com>
pull/1459/head
Victoria 2020-01-03 12:16:01 +01:00 committed by vzotova
parent 519fa00f1a
commit 35a0dd5528
5 changed files with 100 additions and 98 deletions

View File

@ -20,13 +20,13 @@ For a guide of how to deploy these contracts automatically, see the [Deployment
1. Deploy `NuCypherToken` with all future supply tokens
2. Deploy `StakingEscrow` with a dispatcher targeting it
3. Deploy `PolicyManager` with its own dispatcher, also targeting it
4. Deploy `Adjudicator` with a dispatcher
5. Deploy `StakingInterface` with `StakingInterfaceRouter` targeting it
6. Deploy `WorkLock` contract
7. Set the address of the `PolicyManager` contract in the `StakingEscrow` by using the `setPolicyManager(address)`
8. Set the address of the `Adjudicator` contract in the `StakingEscrow` by using the `setAdjudicator(address)`
4. Set the address of the `PolicyManager` contract in the `StakingEscrow` by using the `setPolicyManager(address)`
5. Deploy `Adjudicator` with a dispatcher
6. Set the address of the `Adjudicator` contract in the `StakingEscrow` by using the `setAdjudicator(address)`
7. Deploy `StakingInterface` with `StakingInterfaceRouter` targeting it
8. Deploy `WorkLock` contract
9. Set the address of the `WorkLock` contract in the `StakingEscrow` by using the `setWorkLock(address)`
10. Approve tokens transfer to the `StakingEscrow` contract. These tokens are future mining rewards
10. Approve tokens transfer to the `StakingEscrow` contract. These tokens are future staking rewards
11. Run the `initialize(uint256)` method to initialize the `StakingEscrow` contract
12. Approve tokens transfer for distribution to the `WorkLock` contract and call `tokenDeposit(uint256)` method
13. Pre-deposit tokens to the `PreallocationEscrow`:
@ -44,12 +44,12 @@ In order to take advantage of the network, Alice chooses stakers and deploys pol
Alice can choose stakers by herself ("handpicked") or select from the result of `StakingEscrow.getActiveStakers(uint16, uint256, uint256)` method - This is known as ("sampling").
`getActiveStakers` parameters are:
* Minimum number of periods during which tokens are locked
* Start index for looking in stakers array
* Max stakers for looking
* Start index in stakers array
* Maximum number of stakers
This method will return only active stakers.
In order to place the fee for a policy, Alice calls the method `PolicyManager.createPolicy(bytes16, address, uint64, address[])`,
specifying the staker's addresses, the policy ID (off-chain generation), the policy owner (could be zero address), and the end timestamp of the policy.
specifying the policy ID (off-chain generation), the policy owner (could be zero address), the end timestamp of the policy and the stakers' addresses.
Payment should be added to the transaction in ETH and the amount is `rewardRate * periods * stakers.length`, where `periods` is `endTimestampPeriod - currentPeriod + 1`.
The reward rate must be greater than or equal to the minimum reward for each staker in the list.
@ -58,7 +58,7 @@ The reward rate must be greater than or equal to the minimum reward for each sta
When Alice wants to revoke a policy, she calls the `PolicyManager.revokePolicy(bytes16)` or `PolicyManager.revokeArrangement(bytes16, address)`.
Execution of these methods results in Alice recovering all fees for future periods, and also for periods when the stakers were inactive.
Alice can refund ETH for any inactive periods without revoking the policy by using the method `PolicyManager.refund(bytes16)` or `PolicyManager.refund(bytes16, address)`.
If Alice doesn't have ability to execute on-chain transaction or wants to share ability to revoke then she can sign revocation parameters. Anyone who have this signature will be able to revoke policy using `PolicyManager.revoke(bytes16, address, bytes)`
If Alice can't execute an on-chain transaction or wants to share the ability to revoke, then she can sign revocation parameters. Anyone who has this signature will be able to revoke policy using `PolicyManager.revoke(bytes16, address, bytes)`
## Staker's Contract Interaction

View File

@ -26,7 +26,7 @@ contract PolicyManager is Upgradeable {
event PolicyCreated(
bytes16 indexed policyId,
address indexed creator,
address indexed sponsor,
address indexed owner,
uint256 rewardRate,
uint64 startTimestamp,
@ -68,7 +68,7 @@ contract PolicyManager is Upgradeable {
}
struct Policy {
address payable creator;
address payable sponsor;
address owner;
uint256 rewardRate;
@ -176,7 +176,7 @@ contract PolicyManager is Upgradeable {
uint16 endPeriod = uint16(_endTimestamp / secondsPerPeriod) + 1;
uint256 numberOfPeriods = endPeriod - currentPeriod;
policy.creator = msg.sender;
policy.sponsor = msg.sender;
policy.startTimestamp = uint64(block.timestamp);
policy.endTimestamp = _endTimestamp;
policy.rewardRate = msg.value.div(_nodes.length) / numberOfPeriods;
@ -228,12 +228,12 @@ contract PolicyManager is Upgradeable {
*/
function getPolicyOwner(bytes16 _policyId) public view returns (address) {
Policy storage policy = policies[_policyId];
return policy.owner == address(0) ? policy.creator : policy.owner;
return policy.owner == address(0) ? policy.sponsor : policy.owner;
}
/**
* @notice Set default `rewardDelta` value for specified period
* @dev This method increases gas cost for node in trade of decreasing cost for policy creator
* @dev This method increases gas cost for node in trade of decreasing cost for policy sponsor
* @param _node Node address
* @param _period Period to set
*/
@ -336,7 +336,7 @@ contract PolicyManager is Upgradeable {
}
/**
* @notice Revoke/refund arrangement/policy by the creator
* @notice Revoke/refund arrangement/policy by the sponsor
* @param _policyId Policy id
* @param _node Node that will be excluded or RESERVED_NODE if full policy should be used
( @param _forceRevoke Force revoke arrangement/policy
@ -399,14 +399,14 @@ contract PolicyManager is Upgradeable {
break;
}
}
address payable policyCreator = policy.creator;
address payable policySponsor = policy.sponsor;
if (_node == RESERVED_NODE) {
if (numberOfActive == 0) {
policy.disabled = true;
// gas refund
// deletion more slots will increase gas usage instead of decreasing (in current code)
// because gas refund can be no more than half of all gas
policy.creator = address(0);
policy.sponsor = address(0);
emit PolicyRevoked(_policyId, msg.sender, refundValue);
} else {
emit RefundForPolicy(_policyId, msg.sender, refundValue);
@ -416,7 +416,7 @@ contract PolicyManager is Upgradeable {
require(i < policy.arrangements.length);
}
if (refundValue > 0) {
policyCreator.sendValue(refundValue);
policySponsor.sendValue(refundValue);
}
}
@ -429,7 +429,7 @@ contract PolicyManager is Upgradeable {
internal view returns (uint256 refundValue)
{
Policy storage policy = policies[_policyId];
require((policy.owner == msg.sender || policy.creator == msg.sender) && !policy.disabled);
require((policy.owner == msg.sender || policy.sponsor == msg.sender) && !policy.disabled);
uint256 i = 0;
for (; i < policy.arrangements.length; i++) {
ArrangementInfo storage arrangement = policy.arrangements[i];
@ -449,7 +449,7 @@ contract PolicyManager is Upgradeable {
}
/**
* @notice Revoke policy by the creator
* @notice Revoke policy by the sponsor
* @param _policyId Policy id
*/
function revokePolicy(bytes16 _policyId) public returns (uint256 refundValue) {
@ -458,7 +458,7 @@ contract PolicyManager is Upgradeable {
}
/**
* @notice Revoke arrangement by the creator
* @notice Revoke arrangement by the sponsor
* @param _policyId Policy id
* @param _node Node that will be excluded
*/
@ -474,7 +474,7 @@ contract PolicyManager is Upgradeable {
* @notice Get unsigned hash for revocation
* @param _policyId Policy id
* @param _node Node that will be excluded
* @return Revocation hash
* @return Revocation hash, EIP191 version 0x45 ('E')
*/
function getRevocationHash(bytes16 _policyId, address _node) public view returns (bytes32) {
return SignatureVerifier.hashEIP191(abi.encodePacked(_policyId, _node), byte(0x45));
@ -496,7 +496,7 @@ contract PolicyManager is Upgradeable {
* @notice Revoke policy or arrangement using owner's signature
* @param _policyId Policy id
* @param _node Node that will be excluded, zero address if whole policy will be revoked
* @param _signature Signature of owner
* @param _signature Signature of owner, EIP191 version 0x45 ('E')
*/
function revoke(bytes16 _policyId, address _node, bytes memory _signature)
public returns (uint256 refundValue)
@ -506,17 +506,17 @@ contract PolicyManager is Upgradeable {
}
/**
* @notice Refund part of fee by the creator
* @notice Refund part of fee by the sponsor
* @param _policyId Policy id
*/
function refund(bytes16 _policyId) public {
Policy storage policy = policies[_policyId];
require(policy.owner == msg.sender || policy.creator == msg.sender);
require(policy.owner == msg.sender || policy.sponsor == msg.sender);
refundInternal(_policyId, RESERVED_NODE, false);
}
/**
* @notice Refund part of one node's fee by the creator
* @notice Refund part of one node's fee by the sponsor
* @param _policyId Policy id
* @param _node Node address
*/
@ -525,7 +525,7 @@ contract PolicyManager is Upgradeable {
{
require(_node != RESERVED_NODE);
Policy storage policy = policies[_policyId];
require(policy.owner == msg.sender || policy.creator == msg.sender);
require(policy.owner == msg.sender || policy.sponsor == msg.sender);
return refundInternal(_policyId, _node, false);
}
@ -631,7 +631,7 @@ contract PolicyManager is Upgradeable {
require(uint32(delegateGet(_testTarget, "secondsPerPeriod()")) == secondsPerPeriod);
Policy storage policy = policies[RESERVED_POLICY_ID];
Policy memory policyToCheck = delegateGetPolicy(_testTarget, RESERVED_POLICY_ID);
require(policyToCheck.creator == policy.creator &&
require(policyToCheck.sponsor == policy.sponsor &&
policyToCheck.owner == policy.owner &&
policyToCheck.rewardRate == policy.rewardRate &&
policyToCheck.startTimestamp == policy.startTimestamp &&
@ -668,7 +668,7 @@ contract PolicyManager is Upgradeable {
secondsPerPeriod = policyManager.secondsPerPeriod();
// Create fake Policy and NodeInfo to use them in verifyState(address)
Policy storage policy = policies[RESERVED_POLICY_ID];
policy.creator = msg.sender;
policy.sponsor = msg.sender;
policy.owner = address(this);
policy.startTimestamp = 1;
policy.endTimestamp = 2;

View File

@ -489,7 +489,9 @@ class BlockchainPolicy(Policy):
rate_per_period = self.value // self.n // self.duration_periods # wei
recalculated_value = self.duration_periods * rate_per_period * self.n
if recalculated_value != self.value:
raise ValueError(f"Invalid policy value calculation.") # TODO: Make a better suggestion.
raise ValueError(f"Invalid policy value calculation - "
f"{self.value} can't be divided into {self.n} staker payments per period "
f"for {self.duration_periods} periods without a remainder")
@staticmethod
def generate_policy_parameters(n: int,
@ -504,7 +506,7 @@ class BlockchainPolicy(Policy):
# Check for policy params
if not bool(value) ^ bool(rate):
# TODO: Review this suggestion
raise BlockchainPolicy.InvalidPolicyValue(f"Only one parameter must be provided to calculate policy value and rate.")
raise BlockchainPolicy.InvalidPolicyValue(f"Either 'value' or 'rate' must be provided for policy.")
if not value:
value = rate * duration_periods * n

View File

@ -25,7 +25,7 @@ from web3.contract import Contract
from nucypher.blockchain.eth.interfaces import BlockchainInterface
CREATOR_FIELD = 0
SPONSOR_FIELD = 0
OWNER_FIELD = 1
RATE_FIELD = 2
START_TIMESTAMP_FIELD = 3
@ -47,14 +47,14 @@ POLICY_ID_LENGTH = 16
@pytest.mark.slow
def test_create_revoke(testerchain, escrow, policy_manager):
creator, policy_creator, bad_node, node1, node2, node3, policy_owner, *everyone_else = testerchain.client.accounts
creator, policy_sponsor, bad_node, node1, node2, node3, policy_owner, *everyone_else = testerchain.client.accounts
rate = 20
one_period = 60 * 60
number_of_periods = 10
value = rate * number_of_periods
policy_creator_balance = testerchain.client.get_balance(policy_creator)
policy_sponsor_balance = testerchain.client.get_balance(policy_sponsor)
policy_owner_balance = testerchain.client.get_balance(policy_owner)
policy_created_log = policy_manager.events.PolicyCreated.createFilter(fromBlock='latest')
arrangement_revoked_log = policy_manager.events.ArrangementRevoked.createFilter(fromBlock='latest')
@ -73,36 +73,36 @@ def test_create_revoke(testerchain, escrow, policy_manager):
# Try to create policy for bad (unregistered) node
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.createPolicy(policy_id, policy_creator, end_timestamp, [bad_node])\
.transact({'from': policy_creator, 'value': value})
tx = policy_manager.functions.createPolicy(policy_id, policy_sponsor, end_timestamp, [bad_node])\
.transact({'from': policy_sponsor, 'value': value})
testerchain.wait_for_receipt(tx)
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.createPolicy(policy_id, policy_creator, end_timestamp, [node1, bad_node])\
.transact({'from': policy_creator, 'value': value})
tx = policy_manager.functions.createPolicy(policy_id, policy_sponsor, end_timestamp, [node1, bad_node])\
.transact({'from': policy_sponsor, 'value': value})
testerchain.wait_for_receipt(tx)
# Try to create policy with no ETH
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.createPolicy(policy_id, policy_creator, end_timestamp, [node1])\
.transact({'from': policy_creator})
tx = policy_manager.functions.createPolicy(policy_id, policy_sponsor, end_timestamp, [node1])\
.transact({'from': policy_sponsor})
testerchain.wait_for_receipt(tx)
# Can't create policy using timestamp from the past
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.createPolicy(policy_id, policy_creator, current_timestamp -1, [node1])\
.transact({'from': policy_creator})
tx = policy_manager.functions.createPolicy(policy_id, policy_sponsor, current_timestamp -1, [node1])\
.transact({'from': policy_sponsor})
testerchain.wait_for_receipt(tx)
# Create policy
tx = policy_manager.functions.createPolicy(policy_id, policy_creator, end_timestamp, [node1])\
.transact({'from': policy_creator, 'value': value, 'gas_price': 0})
tx = policy_manager.functions.createPolicy(policy_id, policy_sponsor, end_timestamp, [node1])\
.transact({'from': policy_sponsor, 'value': value, 'gas_price': 0})
testerchain.wait_for_receipt(tx)
current_timestamp = testerchain.w3.eth.getBlock(block_identifier='latest').timestamp
# Check balances and policy info
assert value == testerchain.client.get_balance(policy_manager.address)
assert policy_creator_balance - 200 == testerchain.client.get_balance(policy_creator)
assert policy_sponsor_balance - 200 == testerchain.client.get_balance(policy_sponsor)
policy = policy_manager.functions.policies(policy_id).call()
assert policy_creator == policy[CREATOR_FIELD]
assert policy_sponsor == policy[SPONSOR_FIELD]
assert BlockchainInterface.NULL_ADDRESS == policy[OWNER_FIELD]
assert rate == policy[RATE_FIELD]
assert current_timestamp == policy[START_TIMESTAMP_FIELD]
@ -110,14 +110,14 @@ def test_create_revoke(testerchain, escrow, policy_manager):
assert not policy[DISABLED_FIELD]
assert 1 == policy_manager.functions.getArrangementsLength(policy_id).call()
assert node1 == policy_manager.functions.getArrangementInfo(policy_id, 0).call()[0]
assert policy_creator == policy_manager.functions.getPolicyOwner(policy_id).call()
assert policy_sponsor == policy_manager.functions.getPolicyOwner(policy_id).call()
events = policy_created_log.get_all_entries()
assert 1 == len(events)
event_args = events[0]['args']
assert policy_id == event_args['policyId']
assert policy_creator == event_args['creator']
assert policy_creator == event_args['owner']
assert policy_sponsor == event_args['sponsor']
assert policy_sponsor == event_args['owner']
assert rate == event_args['rewardRate']
assert current_timestamp == event_args['startTimestamp']
assert end_timestamp == event_args['endTimestamp']
@ -125,15 +125,15 @@ def test_create_revoke(testerchain, escrow, policy_manager):
# Can't create policy with the same id
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.createPolicy(policy_id, policy_creator, end_timestamp, [node1])\
.transact({'from': policy_creator, 'value': value})
tx = policy_manager.functions.createPolicy(policy_id, policy_sponsor, end_timestamp, [node1])\
.transact({'from': policy_sponsor, 'value': value})
testerchain.wait_for_receipt(tx)
# Only policy owner can revoke policy
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.revokePolicy(policy_id).transact({'from': creator})
testerchain.wait_for_receipt(tx)
tx = policy_manager.functions.revokePolicy(policy_id).transact({'from': policy_creator, 'gas_price': 0})
tx = policy_manager.functions.revokePolicy(policy_id).transact({'from': policy_sponsor, 'gas_price': 0})
testerchain.wait_for_receipt(tx)
assert policy_manager.functions.policies(policy_id).call()[DISABLED_FIELD]
@ -141,23 +141,23 @@ def test_create_revoke(testerchain, escrow, policy_manager):
assert 1 == len(events)
event_args = events[0]['args']
assert policy_id == event_args['policyId']
assert policy_creator == event_args['sender']
assert policy_sponsor == event_args['sender']
assert value == event_args['value']
events = arrangement_revoked_log.get_all_entries()
assert 1 == len(events)
event_args = events[0]['args']
assert policy_id == event_args['policyId']
assert policy_creator == event_args['sender']
assert policy_sponsor == event_args['sender']
assert node1 == event_args['node']
assert value == event_args['value']
# Can't revoke again because policy and all arrangements are disabled
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.revokePolicy(policy_id).transact({'from': policy_creator})
tx = policy_manager.functions.revokePolicy(policy_id).transact({'from': policy_sponsor})
testerchain.wait_for_receipt(tx)
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.revokeArrangement(policy_id, node1).transact({'from': policy_creator})
tx = policy_manager.functions.revokeArrangement(policy_id, node1).transact({'from': policy_sponsor})
testerchain.wait_for_receipt(tx)
# Create new policy
@ -169,13 +169,13 @@ def test_create_revoke(testerchain, escrow, policy_manager):
end_timestamp = current_timestamp + (number_of_periods - 1) * one_period
policy_id_2 = os.urandom(POLICY_ID_LENGTH)
tx = policy_manager.functions.createPolicy(policy_id_2, policy_owner, end_timestamp, [node1, node2, node3])\
.transact({'from': policy_creator, 'value': 6 * value, 'gas_price': 0})
.transact({'from': policy_sponsor, 'value': 6 * value, 'gas_price': 0})
testerchain.wait_for_receipt(tx)
current_timestamp = testerchain.w3.eth.getBlock(block_identifier='latest').timestamp
assert 6 * value == testerchain.client.get_balance(policy_manager.address)
assert policy_creator_balance - 6 * value == testerchain.client.get_balance(policy_creator)
assert policy_sponsor_balance - 6 * value == testerchain.client.get_balance(policy_sponsor)
policy = policy_manager.functions.policies(policy_id_2).call()
assert policy_creator == policy[CREATOR_FIELD]
assert policy_sponsor == policy[SPONSOR_FIELD]
assert policy_owner == policy[OWNER_FIELD]
assert 2 * rate == policy[RATE_FIELD]
assert current_timestamp == policy[START_TIMESTAMP_FIELD]
@ -187,7 +187,7 @@ def test_create_revoke(testerchain, escrow, policy_manager):
assert 2 == len(events)
event_args = events[1]['args']
assert policy_id_2 == event_args['policyId']
assert policy_creator == event_args['creator']
assert policy_sponsor == event_args['sponsor']
assert policy_owner == event_args['owner']
assert 2 * rate == event_args['rewardRate']
assert current_timestamp == event_args['startTimestamp']
@ -197,26 +197,26 @@ def test_create_revoke(testerchain, escrow, policy_manager):
# Can't revoke nonexistent arrangement
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.revokeArrangement(policy_id_2, testerchain.client.accounts[6])\
.transact({'from': policy_creator})
.transact({'from': policy_sponsor})
testerchain.wait_for_receipt(tx)
# Can't revoke null arrangement (also it's nonexistent)
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.revokeArrangement(policy_id_2, BlockchainInterface.NULL_ADDRESS).transact({'from': policy_creator})
tx = policy_manager.functions.revokeArrangement(policy_id_2, BlockchainInterface.NULL_ADDRESS).transact({'from': policy_sponsor})
testerchain.wait_for_receipt(tx)
# Policy creator can't revoke policy, only owner can
# Policy sponsor can't revoke policy, only owner can
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.revokePolicy(policy_id_2).transact({'from': policy_creator})
tx = policy_manager.functions.revokePolicy(policy_id_2).transact({'from': policy_sponsor})
testerchain.wait_for_receipt(tx)
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.revokeArrangement(policy_id_2, node1).transact({'from': policy_creator})
tx = policy_manager.functions.revokeArrangement(policy_id_2, node1).transact({'from': policy_sponsor})
testerchain.wait_for_receipt(tx)
# Revoke only one arrangement
tx = policy_manager.functions.revokeArrangement(policy_id_2, node1).transact({'from': policy_owner, 'gas_price': 0})
testerchain.wait_for_receipt(tx)
assert 4 * value == testerchain.client.get_balance(policy_manager.address)
assert policy_creator_balance - 4 * value == testerchain.client.get_balance(policy_creator)
assert policy_sponsor_balance - 4 * value == testerchain.client.get_balance(policy_sponsor)
assert not policy_manager.functions.policies(policy_id_2).call()[DISABLED_FIELD]
assert policy_owner_balance == testerchain.client.get_balance(policy_owner)
@ -230,18 +230,18 @@ def test_create_revoke(testerchain, escrow, policy_manager):
# Can't revoke again because arrangement is disabled
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.revokeArrangement(policy_id_2, node1).transact({'from': policy_creator})
tx = policy_manager.functions.revokeArrangement(policy_id_2, node1).transact({'from': policy_sponsor})
testerchain.wait_for_receipt(tx)
# Can't revoke null arrangement (it's nonexistent)
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.revokeArrangement(policy_id_2, BlockchainInterface.NULL_ADDRESS).transact({'from': policy_creator})
tx = policy_manager.functions.revokeArrangement(policy_id_2, BlockchainInterface.NULL_ADDRESS).transact({'from': policy_sponsor})
testerchain.wait_for_receipt(tx)
# Revoke policy with remaining arrangements
tx = policy_manager.functions.revokePolicy(policy_id_2).transact({'from': policy_owner, 'gas_price': 0})
testerchain.wait_for_receipt(tx)
assert 0 == testerchain.client.get_balance(policy_manager.address)
assert policy_creator_balance == testerchain.client.get_balance(policy_creator)
assert policy_sponsor_balance == testerchain.client.get_balance(policy_sponsor)
assert policy_manager.functions.policies(policy_id_2).call()[DISABLED_FIELD]
events = arrangement_revoked_log.get_all_entries()
@ -266,18 +266,18 @@ def test_create_revoke(testerchain, escrow, policy_manager):
# Can't revoke policy again because policy and all arrangements are disabled
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.revokePolicy(policy_id_2).transact({'from': policy_creator})
tx = policy_manager.functions.revokePolicy(policy_id_2).transact({'from': policy_sponsor})
testerchain.wait_for_receipt(tx)
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.revokeArrangement(policy_id_2, node1).transact({'from': policy_creator})
tx = policy_manager.functions.revokeArrangement(policy_id_2, node1).transact({'from': policy_sponsor})
testerchain.wait_for_receipt(tx)
# Can't create policy with wrong ETH value - when reward is not calculated by formula:
# numberOfNodes * rewardRate * numberOfPeriods
policy_id_3 = os.urandom(POLICY_ID_LENGTH)
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.createPolicy(policy_id_3, policy_creator, end_timestamp, [node1])\
.transact({'from': policy_creator, 'value': 11})
tx = policy_manager.functions.createPolicy(policy_id_3, policy_sponsor, end_timestamp, [node1])\
.transact({'from': policy_sponsor, 'value': 11})
testerchain.wait_for_receipt(tx)
# Set minimum reward rate for nodes
@ -292,38 +292,38 @@ def test_create_revoke(testerchain, escrow, policy_manager):
current_timestamp = testerchain.w3.eth.getBlock(block_identifier='latest').timestamp
end_timestamp = current_timestamp + 10
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.createPolicy(policy_id_3, policy_creator, end_timestamp, [node1])\
.transact({'from': policy_creator, 'value': 5})
tx = policy_manager.functions.createPolicy(policy_id_3, policy_sponsor, end_timestamp, [node1])\
.transact({'from': policy_sponsor, 'value': 5})
testerchain.wait_for_receipt(tx)
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.createPolicy(policy_id_3, policy_creator, end_timestamp, [node1, node2])\
.transact({'from': policy_creator, 'value': 30})
tx = policy_manager.functions.createPolicy(policy_id_3, policy_sponsor, end_timestamp, [node1, node2])\
.transact({'from': policy_sponsor, 'value': 30})
testerchain.wait_for_receipt(tx)
# Create new policy
end_timestamp = current_timestamp + (number_of_periods - 1) * one_period
tx = policy_manager.functions.createPolicy(
policy_id_3, BlockchainInterface.NULL_ADDRESS, end_timestamp, [node1, node2]) \
.transact({'from': policy_creator, 'value': 2 * value, 'gas_price': 0})
.transact({'from': policy_sponsor, 'value': 2 * value, 'gas_price': 0})
testerchain.wait_for_receipt(tx)
current_timestamp = testerchain.w3.eth.getBlock(block_identifier='latest').timestamp
assert 2 * value == testerchain.client.get_balance(policy_manager.address)
assert policy_creator_balance - 2 * value == testerchain.client.get_balance(policy_creator)
assert policy_sponsor_balance - 2 * value == testerchain.client.get_balance(policy_sponsor)
policy = policy_manager.functions.policies(policy_id_3).call()
assert policy_creator == policy[CREATOR_FIELD]
assert policy_sponsor == policy[SPONSOR_FIELD]
assert BlockchainInterface.NULL_ADDRESS == policy[OWNER_FIELD]
assert rate == policy[RATE_FIELD]
assert current_timestamp == policy[START_TIMESTAMP_FIELD]
assert end_timestamp == policy[END_TIMESTAMP_FIELD]
assert not policy[DISABLED_FIELD]
assert policy_creator == policy_manager.functions.getPolicyOwner(policy_id_3).call()
assert policy_sponsor == policy_manager.functions.getPolicyOwner(policy_id_3).call()
events = policy_created_log.get_all_entries()
assert 3 == len(events)
event_args = events[2]['args']
assert policy_id_3 == event_args['policyId']
assert policy_creator == event_args['creator']
assert policy_creator == event_args['owner']
assert policy_sponsor == event_args['sponsor']
assert policy_sponsor == event_args['owner']
assert rate == event_args['rewardRate']
assert current_timestamp == event_args['startTimestamp']
assert end_timestamp == event_args['endTimestamp']
@ -336,20 +336,20 @@ def test_create_revoke(testerchain, escrow, policy_manager):
# Only owner's signature can be used
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.revoke(policy_id_3, node1, wrong_signature)\
.transact({'from': policy_creator, 'gas_price': 0})
.transact({'from': policy_sponsor, 'gas_price': 0})
testerchain.wait_for_receipt(tx)
signature = testerchain.client.sign_message(account=policy_creator, message=data)
signature = testerchain.client.sign_message(account=policy_sponsor, message=data)
tx = policy_manager.functions.revoke(policy_id_3, node1, signature)\
.transact({'from': policy_creator, 'gas_price': 0})
.transact({'from': policy_sponsor, 'gas_price': 0})
testerchain.wait_for_receipt(tx)
assert value == testerchain.client.get_balance(policy_manager.address)
assert policy_creator_balance - value == testerchain.client.get_balance(policy_creator)
assert policy_sponsor_balance - value == testerchain.client.get_balance(policy_sponsor)
assert not policy_manager.functions.policies(policy_id_3).call()[DISABLED_FIELD]
assert BlockchainInterface.NULL_ADDRESS == policy_manager.functions.getArrangementInfo(policy_id_3, 0).call()[0]
assert node2 == policy_manager.functions.getArrangementInfo(policy_id_3, 1).call()[0]
data = policy_id_3 + to_canonical_address(BlockchainInterface.NULL_ADDRESS)
signature = testerchain.client.sign_message(account=policy_creator, message=data)
signature = testerchain.client.sign_message(account=policy_sponsor, message=data)
tx = policy_manager.functions.revoke(policy_id_3, BlockchainInterface.NULL_ADDRESS, signature)\
.transact({'from': creator, 'gas_price': 0})
testerchain.wait_for_receipt(tx)
@ -359,11 +359,11 @@ def test_create_revoke(testerchain, escrow, policy_manager):
end_timestamp = current_timestamp + (number_of_periods - 1) * one_period
policy_id_4 = os.urandom(POLICY_ID_LENGTH)
tx = policy_manager.functions.createPolicy(policy_id_4, policy_owner, end_timestamp, [node1, node2, node3]) \
.transact({'from': policy_creator, 'value': 3 * value, 'gas_price': 0})
.transact({'from': policy_sponsor, 'value': 3 * value, 'gas_price': 0})
testerchain.wait_for_receipt(tx)
data = policy_id_4 + to_canonical_address(BlockchainInterface.NULL_ADDRESS)
wrong_signature = testerchain.client.sign_message(account=policy_creator, message=data)
wrong_signature = testerchain.client.sign_message(account=policy_sponsor, message=data)
# Only owner's signature can be used
with pytest.raises((TransactionFailed, ValueError)):
tx = policy_manager.functions.revoke(policy_id_4, BlockchainInterface.NULL_ADDRESS, wrong_signature)\

View File

@ -23,7 +23,7 @@ from eth_tester.exceptions import TransactionFailed
from nucypher.blockchain.eth.interfaces import BlockchainInterface
CREATOR_FIELD = 0
SPONSOR_FIELD = 0
OWNER_FIELD = 1
RATE_FIELD = 2
START_TIMESTAMP_FIELD = 3
@ -47,7 +47,7 @@ value = rate * number_of_periods
@pytest.mark.slow
def test_reward(testerchain, escrow, policy_manager):
creator, policy_creator, bad_node, node1, node2, node3, *everyone_else = testerchain.client.accounts
creator, policy_sponsor, bad_node, node1, node2, node3, *everyone_else = testerchain.client.accounts
node_balance = testerchain.client.get_balance(node1)
withdraw_log = policy_manager.events.Withdrawn.createFilter(fromBlock='latest')
@ -62,8 +62,8 @@ def test_reward(testerchain, escrow, policy_manager):
testerchain.wait_for_receipt(tx)
current_timestamp = testerchain.w3.eth.getBlock(block_identifier='latest').timestamp
end_timestamp = current_timestamp + (number_of_periods - 1) * one_period
tx = policy_manager.functions.createPolicy(policy_id, policy_creator, end_timestamp, [node1, node3])\
.transact({'from': policy_creator, 'value': 2 * value})
tx = policy_manager.functions.createPolicy(policy_id, policy_sponsor, end_timestamp, [node1, node3])\
.transact({'from': policy_sponsor, 'value': 2 * value})
testerchain.wait_for_receipt(tx)
# Nothing to withdraw
@ -131,8 +131,8 @@ def test_reward(testerchain, escrow, policy_manager):
period = escrow.functions.getCurrentPeriod().call()
tx = escrow.functions.setDefaultRewardDelta(node1, period, 1).transact()
testerchain.wait_for_receipt(tx)
tx = policy_manager.functions.createPolicy(policy_id_2, policy_creator, end_timestamp, [node2, node3]) \
.transact({'from': policy_creator, 'value': int(2 * value)})
tx = policy_manager.functions.createPolicy(policy_id_2, policy_sponsor, end_timestamp, [node2, node3]) \
.transact({'from': policy_sponsor, 'value': int(2 * value)})
testerchain.wait_for_receipt(tx)
# Mint some periods
@ -201,7 +201,7 @@ def test_refund(testerchain, escrow, policy_manager):
testerchain.wait_for_receipt(tx)
assert 20 == testerchain.client.get_balance(policy_manager.address)
assert creator_balance - 20 == testerchain.client.get_balance(policy_creator)
assert policy_creator == policy_manager.functions.policies(policy_id).call()[CREATOR_FIELD]
assert policy_creator == policy_manager.functions.policies(policy_id).call()[SPONSOR_FIELD]
events = arrangement_refund_log.get_all_entries()
assert 1 == len(events)