mirror of https://github.com/nucypher/nucypher.git
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
parent
519fa00f1a
commit
35a0dd5528
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)\
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue