Added payment for the first/current period when creating a policy

pull/261/head
szotov 2018-04-11 16:55:04 +03:00
parent c22be3f6d8
commit b1d8ae9816
3 changed files with 227 additions and 87 deletions

View File

@ -53,10 +53,11 @@ contract PolicyManager is Upgradeable {
IndexOfDowntimePeriods,
LastRefundedPeriod,
ArrangementDisabled,
Rate,
RewardRate,
StartPeriod,
LastPeriod,
Disabled
Disabled,
FirstReward
}
enum NodeInfoField {
@ -78,7 +79,8 @@ contract PolicyManager is Upgradeable {
address[] nodes;
// policy for activity periods
uint256 rate;
uint256 rewardRate;
uint256 firstReward;
uint256 startPeriod;
uint256 lastPeriod;
bool disabled;
@ -111,22 +113,23 @@ contract PolicyManager is Upgradeable {
* @notice Create policy by client
* @dev Generate policy id before creation
* @param _policyId Policy id
* @param _numberOfPeriods Duration of the policy in periods
* @param _numberOfPeriods Duration of the policy in periods except first period
* @param _firstReward Reward for first period
* @param _nodes Nodes that will handle policy
**/
function createPolicy(
bytes20 _policyId,
uint256 _numberOfPeriods,
uint256 _firstReward,
address[] _nodes
)
public payable
{
require(
policies[_policyId].rate == 0 &&
_policyId != RESERVED_POLICY_ID &&
policies[_policyId].rewardRate == 0 &&
_numberOfPeriods != 0 &&
msg.value > 0 &&
msg.value % _numberOfPeriods % _nodes.length == 0 &&
_policyId != RESERVED_POLICY_ID
msg.value > 0
);
Policy storage policy = policies[_policyId];
policy.client = msg.sender;
@ -134,21 +137,24 @@ contract PolicyManager is Upgradeable {
uint256 currentPeriod = escrow.getCurrentPeriod();
policy.startPeriod = currentPeriod.add(uint(1));
policy.lastPeriod = currentPeriod.add(_numberOfPeriods);
uint256 feeByPeriod = msg.value.div(_numberOfPeriods).div(_nodes.length);
policy.rate = feeByPeriod;
policy.rewardRate = msg.value.div(_nodes.length).sub(_firstReward).div(_numberOfPeriods);
policy.firstReward = _firstReward;
require(policy.rewardRate > _firstReward &&
(_firstReward + policy.rewardRate * _numberOfPeriods) * _nodes.length == msg.value);
uint256 endPeriod = policy.lastPeriod.add(uint(1));
uint256 startReward = policy.rewardRate - _firstReward;
policy.nodes = _nodes;
for (uint256 i = 0; i < _nodes.length; i++) {
require(escrow.getLockedTokens(_nodes[i]) != 0 &&
_nodes[i] != RESERVED_NODE);
require(escrow.getLockedTokens(_nodes[i]) != 0 && _nodes[i] != RESERVED_NODE);
NodeInfo storage node = nodes[_nodes[i]];
node.rewardDelta[currentPeriod] = node.rewardDelta[currentPeriod].add(_firstReward);
node.rewardDelta[policy.startPeriod] = node.rewardDelta[policy.startPeriod]
.add(feeByPeriod);
node.rewardDelta[endPeriod] = node.rewardDelta[endPeriod].sub(feeByPeriod);
.add(startReward);
node.rewardDelta[endPeriod] = node.rewardDelta[endPeriod].sub(policy.rewardRate);
// TODO node should pay for this
if (node.lastMinedPeriod == 0) {
node.lastMinedPeriod = currentPeriod;
node.lastMinedPeriod = currentPeriod.sub(uint256(1));
}
ArrangementInfo storage arrangement = policy.arrangements[_nodes[i]];
arrangement.indexOfDowntimePeriods =
@ -248,10 +254,10 @@ contract PolicyManager is Upgradeable {
NodeInfo storage node = nodes[_node];
ArrangementInfo storage arrangement = _policy.arrangements[_node];
node.rewardDelta[arrangement.lastRefundedPeriod] =
node.rewardDelta[arrangement.lastRefundedPeriod].sub(_policy.rate);
node.rewardDelta[_endPeriod] = node.rewardDelta[_endPeriod].add(_policy.rate);
node.rewardDelta[arrangement.lastRefundedPeriod].sub(_policy.rewardRate);
node.rewardDelta[_endPeriod] = node.rewardDelta[_endPeriod].add(_policy.rewardRate);
refundValue = refundValue.add(
_endPeriod.sub(arrangement.lastRefundedPeriod).mul(_policy.rate));
_endPeriod.sub(arrangement.lastRefundedPeriod).mul(_policy.rewardRate));
_policy.arrangements[_node].active = false;
}
@ -315,7 +321,7 @@ contract PolicyManager is Upgradeable {
* @param _node Node for calculation
**/
//TODO extract checkRefund method
function calculateRefund(Policy storage _policy, address _node) internal returns (uint256) {
function calculateRefund(Policy storage _policy, address _node) internal returns (uint256 refundValue) {
ArrangementInfo storage arrangement = _policy.arrangements[_node];
uint256 maxPeriod = Math.min256(escrow.getCurrentPeriod(), _policy.lastPeriod);
uint256 minPeriod = Math.max256(_policy.startPeriod, arrangement.lastRefundedPeriod);
@ -339,7 +345,7 @@ contract PolicyManager is Upgradeable {
break;
}
}
arrangement.indexOfDowntimePeriods = i;
uint256 lastActivePeriod =
uint256(escrow.getMinerInfo(MinersEscrow.MinerInfoField.LastActivePeriod, _node, 0));
if (i == length && lastActivePeriod < maxPeriod) {
@ -347,9 +353,25 @@ contract PolicyManager is Upgradeable {
maxPeriod.sub(Math.max256(
minPeriod.sub(uint(1)), lastActivePeriod)));
}
arrangement.lastRefundedPeriod = maxPeriod.add(uint(1));
return _policy.rate.mul(downtimePeriods);
// TODO refactor
if (arrangement.lastRefundedPeriod == 0) {
if (lastActivePeriod < _policy.startPeriod - 1) {
refundValue = _policy.firstReward;
} else if (arrangement.indexOfDowntimePeriods < length) {
startPeriod = uint256(escrow.getMinerInfo(MinersEscrow.MinerInfoField.DowntimeStartPeriod,
_node, arrangement.indexOfDowntimePeriods));
endPeriod = uint256(escrow.getMinerInfo(MinersEscrow.MinerInfoField.DowntimeEndPeriod,
_node, arrangement.indexOfDowntimePeriods));
if (_policy.startPeriod > startPeriod && _policy.startPeriod - 1 <= endPeriod) {
refundValue = _policy.firstReward;
}
}
}
refundValue = refundValue.add(_policy.rewardRate.mul(downtimePeriods));
arrangement.indexOfDowntimePeriods = i;
arrangement.lastRefundedPeriod = maxPeriod.add(uint(1));
}
/**
@ -385,8 +407,8 @@ contract PolicyManager is Upgradeable {
Policy storage policy = policies[_policyId];
if (_field == PolicyInfoField.Client) {
return bytes32(policy.client);
} else if (_field == PolicyInfoField.Rate) {
return bytes32(policy.rate);
} else if (_field == PolicyInfoField.RewardRate) {
return bytes32(policy.rewardRate);
} else if (_field == PolicyInfoField.StartPeriod) {
return bytes32(policy.startPeriod);
} else if (_field == PolicyInfoField.LastPeriod) {
@ -399,6 +421,8 @@ contract PolicyManager is Upgradeable {
return bytes32(policy.arrangements[_node].lastRefundedPeriod);
} else if (_field == PolicyInfoField.ArrangementDisabled) {
return !policy.arrangements[_node].active ? bytes32(1) : bytes32(0);
} else if (_field == PolicyInfoField.FirstReward) {
return bytes32(policy.firstReward);
}
}
@ -429,7 +453,9 @@ contract PolicyManager is Upgradeable {
require(address(delegateGet(_testTarget, "getPolicyInfo(uint8,bytes20,address)",
bytes32(uint8(PolicyInfoField.Client)), RESERVED_POLICY_ID, 0x0)) == policy.client);
require(uint256(delegateGet(_testTarget, "getPolicyInfo(uint8,bytes20,address)",
bytes32(uint8(PolicyInfoField.Rate)), RESERVED_POLICY_ID, 0x0)) == policy.rate);
bytes32(uint8(PolicyInfoField.RewardRate)), RESERVED_POLICY_ID, 0x0)) == policy.rewardRate);
require(uint256(delegateGet(_testTarget, "getPolicyInfo(uint8,bytes20,address)",
bytes32(uint8(PolicyInfoField.FirstReward)), RESERVED_POLICY_ID, 0x0)) == policy.firstReward);
require(uint256(delegateGet(_testTarget, "getPolicyInfo(uint8,bytes20,address)",
bytes32(uint8(PolicyInfoField.StartPeriod)), RESERVED_POLICY_ID, 0x0)) == policy.startPeriod);
require(uint256(delegateGet(_testTarget, "getPolicyInfo(uint8,bytes20,address)",
@ -468,7 +494,8 @@ contract PolicyManager is Upgradeable {
policy.client = owner;
policy.startPeriod = 1;
policy.lastPeriod = 2;
policy.rate = 3;
policy.rewardRate = 3;
policy.firstReward = 4;
policy.disabled = true;
policy.nodes.push(RESERVED_NODE);
policy.arrangements[RESERVED_NODE].indexOfDowntimePeriods = 11;

View File

@ -265,24 +265,24 @@ def test_all(web3, chain, token, escrow, policy_manager):
# Create policies
policy_id_1 = os.urandom(20)
tx = policy_manager.transact({'from': alice1, 'value': 2 * 1000, 'gas_price': 0}) \
.createPolicy(policy_id_1, 5, [ursula1, ursula2])
tx = policy_manager.transact({'from': alice1, 'value': 2 * 1000 + 2 * 44, 'gas_price': 0}) \
.createPolicy(policy_id_1, 5, 44, [ursula1, ursula2])
chain.wait_for_receipt(tx)
policy_id_2 = os.urandom(20)
tx = policy_manager.transact({'from': alice1, 'value': 2 * 1000, 'gas_price': 0}) \
.createPolicy(policy_id_2, 5, [ursula2, user_escrow_1.address])
tx = policy_manager.transact({'from': alice1, 'value': 2 * 1000 + 2 * 44, 'gas_price': 0}) \
.createPolicy(policy_id_2, 5, 44, [ursula2, user_escrow_1.address])
chain.wait_for_receipt(tx)
policy_id_3 = os.urandom(20)
tx = policy_manager.transact({'from': alice2, 'value': 2 * 1000, 'gas_price': 0}) \
.createPolicy(policy_id_3, 5, [ursula1, user_escrow_1.address])
tx = policy_manager.transact({'from': alice2, 'value': 2 * 1000 + 2 * 44, 'gas_price': 0}) \
.createPolicy(policy_id_3, 5, 44, [ursula1, user_escrow_1.address])
chain.wait_for_receipt(tx)
policy_id_4 = os.urandom(20)
tx = policy_manager.transact({'from': alice2, 'value': 2 * 1000, 'gas_price': 0}) \
.createPolicy(policy_id_4, 5, [ursula2, user_escrow_1.address])
tx = policy_manager.transact({'from': alice2, 'value': 2 * 1000 + 2 * 44, 'gas_price': 0}) \
.createPolicy(policy_id_4, 5, 44, [ursula2, user_escrow_1.address])
chain.wait_for_receipt(tx)
policy_id_5 = os.urandom(20)
tx = policy_manager.transact({'from': alice2, 'value': 2 * 1000, 'gas_price': 0}) \
.createPolicy(policy_id_5, 5, [ursula1, ursula2])
tx = policy_manager.transact({'from': alice2, 'value': 2 * 1000 + 2 * 44, 'gas_price': 0}) \
.createPolicy(policy_id_5, 5, 44, [ursula1, ursula2])
chain.wait_for_receipt(tx)
# Only Alice can revoke policy
@ -292,7 +292,7 @@ def test_all(web3, chain, token, escrow, policy_manager):
alice2_balance = web3.eth.getBalance(alice2)
tx = policy_manager.transact({'from': alice2, 'gas_price': 0}).revokePolicy(policy_id_5)
chain.wait_for_receipt(tx)
assert 8000 == web3.eth.getBalance(policy_manager.address)
assert 8440 == web3.eth.getBalance(policy_manager.address)
assert alice2_balance + 2000 == web3.eth.getBalance(alice2)
assert 1 == web3.toInt(
policy_manager.call().getPolicyInfo(DISABLED_FIELD, policy_id_5, NULL_ADDR))
@ -309,7 +309,7 @@ def test_all(web3, chain, token, escrow, policy_manager):
tx = policy_manager.transact({'from': alice1, 'gas_price': 0}) \
.revokeArrangement(policy_id_2, ursula2)
chain.wait_for_receipt(tx)
assert 7000 == web3.eth.getBalance(policy_manager.address)
assert 7440 == web3.eth.getBalance(policy_manager.address)
assert alice1_balance + 1000 == web3.eth.getBalance(alice1)
assert 0 == web3.toInt(
policy_manager.call().getPolicyInfo(DISABLED_FIELD, policy_id_2, NULL_ADDR))

View File

@ -12,6 +12,7 @@ RATE_FIELD = 4
START_PERIOD_FIELD = 5
LAST_PERIOD_FIELD = 6
DISABLED_FIELD = 7
FIRST_REWARD_FIELD = 8
REWARD_FIELD = 0
REWARD_RATE_FIELD = 1
@ -93,29 +94,31 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
# Try create policy for bad node
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client, 'value': value})\
.createPolicy(policy_id, 1, [bad_node])
.createPolicy(policy_id, 1, 0, [bad_node])
chain.wait_for_receipt(tx)
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client, 'value': value})\
.createPolicy(policy_id, 1, [node1, bad_node])
.createPolicy(policy_id, 1, 0, [node1, bad_node])
chain.wait_for_receipt(tx)
# Try create policy with no ETH
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client})\
.createPolicy(policy_id, 1, [node1])
.createPolicy(policy_id, 1, 0, [node1])
chain.wait_for_receipt(tx)
# Create policy
period = escrow.call().getCurrentPeriod()
tx = policy_manager.transact({'from': client, 'value': value, 'gas_price': 0})\
.createPolicy(policy_id, number_of_periods, [node1])
.createPolicy(policy_id, number_of_periods, 0, [node1])
chain.wait_for_receipt(tx)
assert 200 == web3.eth.getBalance(policy_manager.address)
assert value == web3.eth.getBalance(policy_manager.address)
assert client_balance - 200 == web3.eth.getBalance(client)
# getPolicyInfo returns 32 bytes, where first 12 bytes is zero because of address format
assert client == web3.toChecksumAddress(
policy_manager.call().getPolicyInfo(CLIENT_FIELD, policy_id, NULL_ADDR)[12:])
assert rate == web3.toInt(policy_manager.call().getPolicyInfo(RATE_FIELD, policy_id, NULL_ADDR))
assert 0 == web3.toInt(
policy_manager.call().getPolicyInfo(FIRST_REWARD_FIELD, policy_id, NULL_ADDR))
assert period + 1 == web3.toInt(
policy_manager.call().getPolicyInfo(START_PERIOD_FIELD, policy_id, NULL_ADDR))
assert period + 10 == web3.toInt(
@ -135,7 +138,7 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
# Try to create policy again
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client, 'value': value}) \
.createPolicy(policy_id, number_of_periods, [node1])
.createPolicy(policy_id, number_of_periods, 0, [node1])
chain.wait_for_receipt(tx)
# Only client can revoke policy
@ -172,14 +175,17 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
# Create another policy
period = escrow.call().getCurrentPeriod()
tx = policy_manager.transact({'from': client, 'value': 3 * value, 'gas_price': 0})\
.createPolicy(policy_id_2, number_of_periods, [node1, node2, node3])
tx = policy_manager.transact({'from': client, 'value': 6 * value, 'gas_price': 0})\
.createPolicy(policy_id_2, number_of_periods, 0, [node1, node2, node3])
chain.wait_for_receipt(tx)
assert 3 * value == web3.eth.getBalance(policy_manager.address)
assert client_balance - 3 * value == web3.eth.getBalance(client)
assert 6 * value == web3.eth.getBalance(policy_manager.address)
assert client_balance - 6 * value == web3.eth.getBalance(client)
assert client == web3.toChecksumAddress(
policy_manager.call().getPolicyInfo(CLIENT_FIELD, policy_id_2, NULL_ADDR)[12:])
assert rate == web3.toInt(policy_manager.call().getPolicyInfo(RATE_FIELD, policy_id_2, NULL_ADDR))
assert 2 * rate == web3.toInt(
policy_manager.call().getPolicyInfo(RATE_FIELD, policy_id_2, NULL_ADDR))
assert 0 == web3.toInt(
policy_manager.call().getPolicyInfo(FIRST_REWARD_FIELD, policy_id_2, NULL_ADDR))
assert period + 1 == web3.toInt(
policy_manager.call().getPolicyInfo(START_PERIOD_FIELD, policy_id_2, NULL_ADDR))
assert period + 10 == web3.toInt(
@ -203,8 +209,8 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
tx = policy_manager.transact({'from': client, 'gas_price': 0})\
.revokeArrangement(policy_id_2, node1)
chain.wait_for_receipt(tx)
assert 2 * value == web3.eth.getBalance(policy_manager.address)
assert client_balance - 2 * value == web3.eth.getBalance(client)
assert 4 * value == web3.eth.getBalance(policy_manager.address)
assert client_balance - 4 * value == web3.eth.getBalance(client)
assert 0 == web3.toInt(
policy_manager.call().getPolicyInfo(DISABLED_FIELD, policy_id_2, NULL_ADDR))
@ -215,7 +221,7 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
assert policy_id_2 == event_args['policyId']
assert client == event_args['client']
assert node1 == event_args['node']
assert value == event_args['value']
assert 2 * value == event_args['value']
# Can't revoke again
with pytest.raises(TransactionFailed):
@ -236,20 +242,20 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
assert policy_id_2 == event_args['policyId']
assert client == event_args['client']
assert node2 == event_args['node']
assert value == event_args['value']
assert 2 * value == event_args['value']
event_args = events[3]['args']
assert policy_id_2 == event_args['policyId']
assert client == event_args['client']
assert node3 == event_args['node']
assert value == event_args['value']
assert 2 * value == event_args['value']
events = policy_revoked_log.get_all_entries()
assert 2 == len(events)
event_args = events[1]['args']
assert policy_id_2 == event_args['policyId']
assert client == event_args['client']
assert 2 * value == event_args['value']
assert 4 * value == event_args['value']
# Can't revoke again
with pytest.raises(TransactionFailed):
@ -259,6 +265,88 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
tx = policy_manager.transact({'from': client}).revokeArrangement(policy_id_2, node1)
chain.wait_for_receipt(tx)
# Try create policy with wrong value
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client, 'value': 11}) \
.createPolicy(policy_id, 10, 0, [node1])
chain.wait.for_receipt(tx)
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client, 'value': 12}) \
.createPolicy(policy_id, 10, 1, [node1])
chain.wait.for_receipt(tx)
# Create another policy with pay for first period
# Reward rate is calculated as (firstReward + rewardRate * numberOfPeriods) * numberOfNodes
period = escrow.call().getCurrentPeriod()
tx = policy_manager.transact({'from': client,
'value': int((0.5 * rate + rate * number_of_periods) * 3),
'gas_price': 0})\
.createPolicy(policy_id_3, number_of_periods, int(0.5 * rate), [node1, node2, node3])
chain.wait.for_receipt(tx)
assert 3 * value + 1.5 * rate == web3.eth.getBalance(policy_manager.address)
assert client_balance - int(3 * value + 1.5 * rate) == web3.eth.getBalance(client)
assert client == web3.toChecksumAddress(
policy_manager.call().getPolicyInfo(CLIENT_FIELD, policy_id_3, NULL_ADDR))
assert rate == web3.toInt(
policy_manager.call().getPolicyInfo(RATE_FIELD, policy_id_3, NULL_ADDR))
assert 0.5 * rate == web3.toInt(
policy_manager.call().getPolicyInfo(FIRST_REWARD_FIELD, policy_id_3, NULL_ADDR))
assert period + 1 == web3.toInt(
policy_manager.call().getPolicyInfo(START_PERIOD_FIELD, policy_id_3, NULL_ADDR))
assert period + 10 == web3.toInt(
policy_manager.call().getPolicyInfo(LAST_PERIOD_FIELD, policy_id_3, NULL_ADDR))
assert 0 == web3.toInt(
policy_manager.call().getPolicyInfo(DISABLED_FIELD, policy_id_3, NULL_ADDR))
events = policy_created_log.get_all_entries()
assert 3 == len(events)
event_args = events[2]['args']
assert policy_id_3 == event_args['policyId']
assert client == event_args['client']
# assert node == event_args['node']
tx = policy_manager.transact({'from': client, 'gas_price': 0}) \
.revokeArrangement(policy_id_3, node1)
chain.wait.for_receipt(tx)
assert 2 * value + rate == web3.eth.getBalance(policy_manager.address)
assert client_balance - (2 * value + rate) == web3.eth.getBalance(client)
assert 0 == web3.toInt(
policy_manager.call().getPolicyInfo(DISABLED_FIELD, policy_id_3, NULL_ADDR))
events = arrangement_revoked_log.get_all_entries()
assert 5 == len(events)
event_args = events[4]['args']
assert policy_id_3 == event_args['policyId']
assert client == event_args['client']
assert node1 == event_args['node']
assert value + 0.5 * rate == event_args['value']
tx = policy_manager.transact({'from': client, 'gas_price': 0}).revokePolicy(policy_id_3)
chain.wait.for_receipt(tx)
assert 0 == web3.eth.getBalance(policy_manager.address)
assert client_balance == web3.eth.getBalance(client)
assert 1 == web3.toInt(
policy_manager.call().getPolicyInfo(DISABLED_FIELD, policy_id_3, NULL_ADDR))
events = arrangement_revoked_log.get_all_entries()
assert 7 == len(events)
event_args = events[5]['args']
assert policy_id_3 == event_args['policyId']
assert client == event_args['client']
assert node2 == event_args['node']
assert value + 0.5 * rate == event_args['value']
event_args = events[6]['args']
assert policy_id_3 == event_args['policyId']
assert client == event_args['client']
assert node3 == event_args['node']
assert value + 0.5 * rate == event_args['value']
events = policy_revoked_log.get_all_entries()
assert 3 == len(events)
event_args = events[2]['args']
assert policy_id_3 == event_args['policyId']
assert client == event_args['client']
assert 2 * value + rate == event_args['value']
events = arrangement_refund_log.get_all_entries()
assert 0 == len(events)
events = policy_refund_log.get_all_entries()
@ -266,10 +354,7 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
def test_reward(web3, chain, escrow, policy_manager):
client = web3.eth.accounts[1]
node1 = web3.eth.accounts[3]
node2 = web3.eth.accounts[4]
node3 = web3.eth.accounts[5]
creator, client, bad_node, node1, node2, node3, *everyone_else = web3.eth.accounts
node_balance = web3.eth.getBalance(node1)
withdraw_log = policy_manager.eventFilter('Withdrawn')
@ -280,8 +365,8 @@ def test_reward(web3, chain, escrow, policy_manager):
assert 0 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node1, 0))
# Create policy
tx = policy_manager.transact({'from': client, 'value': 3 * value})\
.createPolicy(policy_id, number_of_periods, [node1, node2, node3])
tx = policy_manager.transact({'from': client, 'value': 2 * value})\
.createPolicy(policy_id, number_of_periods, 0, [node1, node3])
chain.wait_for_receipt(tx)
# Nothing to withdraw
@ -304,7 +389,7 @@ def test_reward(web3, chain, escrow, policy_manager):
tx = policy_manager.transact({'from': node1, 'gas_price': 0}).withdraw()
chain.wait_for_receipt(tx)
assert node_balance + 80 == web3.eth.getBalance(node1)
assert 120 + 2 * value == web3.eth.getBalance(policy_manager.address)
assert 120 + value == web3.eth.getBalance(policy_manager.address)
events = withdraw_log.get_all_entries()
assert 1 == len(events)
@ -313,17 +398,20 @@ def test_reward(web3, chain, escrow, policy_manager):
assert 80 == event_args['value']
# Mint more periods
for x in range(20):
for x in range(6):
tx = escrow.transact({'from': node1, 'gas_price': 0}).mint(period, 1)
chain.wait_for_receipt(tx)
period += 1
assert 120 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node1, 0))
tx = escrow.transact({'from': node1, 'gas_price': 0}).mint(period, 1)
chain.wait.for_receipt(tx)
assert 120 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node1, 0))
# Withdraw
tx = policy_manager.transact({'from': node1, 'gas_price': 0}).withdraw()
chain.wait_for_receipt(tx)
assert node_balance + value == web3.eth.getBalance(node1)
assert 2 * value == web3.eth.getBalance(policy_manager.address)
assert value == web3.eth.getBalance(policy_manager.address)
events = withdraw_log.get_all_entries()
assert 2 == len(events)
@ -331,6 +419,25 @@ def test_reward(web3, chain, escrow, policy_manager):
assert node1 == event_args['node']
assert 120 == event_args['value']
# Create policy
tx = policy_manager.transact({'from': client, 'value': int(2 * value + rate)}) \
.createPolicy(policy_id_2, number_of_periods, int(0.5 * rate), [node2, node3])
chain.wait.for_receipt(tx)
# Mint some periods
period = escrow.call().getCurrentPeriod()
tx = escrow.transact({'from': node2, 'gas_price': 0}).mint(period, 5)
chain.wait.for_receipt(tx)
period += 5
assert 90 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node2, 0))
# Mint more periods
for x in range(6):
tx = escrow.transact({'from': node2, 'gas_price': 0}).mint(period, 1)
chain.wait.for_receipt(tx)
period += 1
assert 210 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node2, 0))
def test_refund(web3, chain, escrow, policy_manager):
client = web3.eth.accounts[1]
@ -345,10 +452,10 @@ def test_refund(web3, chain, escrow, policy_manager):
policy_refund_log = policy_manager.eventFilter('RefundForPolicy')
# Create policy
tx = policy_manager.transact({'from': client, 'value': value, 'gas_price': 0}) \
.createPolicy(policy_id, number_of_periods, [node1])
tx = policy_manager.transact({'from': client, 'value': int(value + 0.5 * rate), 'gas_price': 0}) \
.createPolicy(policy_id, number_of_periods, int(0.5 * rate), [node1])
chain.wait_for_receipt(tx)
tx = escrow.transact().setLastActivePeriod(escrow.call().getCurrentPeriod())
tx = escrow.transact().setLastActivePeriod(escrow.call().getCurrentPeriod() - 1)
chain.wait_for_receipt(tx)
# Wait and refund all
@ -367,14 +474,14 @@ def test_refund(web3, chain, escrow, policy_manager):
assert policy_id == event_args['policyId']
assert client == event_args['client']
assert node1 == event_args['node']
assert 180 == event_args['value']
assert 190 == event_args['value']
events = policy_refund_log.get_all_entries()
assert 1 == len(events)
event_args = events[0]['args']
assert policy_id == event_args['policyId']
assert client == event_args['client']
assert 180 == event_args['value']
assert 190 == event_args['value']
wait_time(chain, 1)
tx = policy_manager.transact({'from': client, 'gas_price': 0}).refund(policy_id)
@ -409,9 +516,12 @@ def test_refund(web3, chain, escrow, policy_manager):
chain.wait_for_receipt(tx)
# Create policy again
wait_time(chain, 1)
period = escrow.call().getCurrentPeriod()
tx = policy_manager.transact({'from': client, 'value': 3 * value, 'gas_price': 0})\
.createPolicy(policy_id_2, number_of_periods, [node1, node2, node3])
tx = escrow.transact().setLastActivePeriod(period)
chain.wait_for_receipt(tx)
tx = policy_manager.transact({'from': client, 'value': int(3 * value + 1.5 * rate), 'gas_price': 0})\
.createPolicy(policy_id_2, number_of_periods, int(0.5 * rate), [node1, node2, node3])
chain.wait_for_receipt(tx)
# Nothing to refund
@ -419,8 +529,8 @@ def test_refund(web3, chain, escrow, policy_manager):
chain.wait_for_receipt(tx)
tx = policy_manager.transact({'from': client, 'gas_price': 0}).refund(policy_id_2, node1)
chain.wait_for_receipt(tx)
assert 3 * value == web3.eth.getBalance(policy_manager.address)
assert client_balance - 3 * value == web3.eth.getBalance(client)
assert 3 * value + 1.5 * rate == web3.eth.getBalance(policy_manager.address)
assert client_balance - int(3 * value + 1.5 * rate) == web3.eth.getBalance(client)
events = arrangement_refund_log.get_all_entries()
assert 6 == len(events)
event_args = events[2]['args']
@ -465,6 +575,8 @@ def test_refund(web3, chain, escrow, policy_manager):
chain.wait_for_receipt(tx)
# Mint some periods and mark others as downtime periods
tx = escrow.transact({'from': node1}).mint(period, 1)
chain.wait_for_receipt(tx)
period += 1
tx = escrow.transact({'from': node1}).mint(period, 2)
chain.wait_for_receipt(tx)
@ -478,14 +590,14 @@ def test_refund(web3, chain, escrow, policy_manager):
chain.wait_for_receipt(tx)
tx = escrow.transact().setLastActivePeriod(period + 8)
chain.wait_for_receipt(tx)
assert 80 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node1, 0))
assert 90 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node1, 0))
# Wait and refund
wait_time(chain, 10)
tx = policy_manager.transact({'from': client, 'gas_price': 0}).refund(policy_id_2, node1)
chain.wait_for_receipt(tx)
assert 2 * value + 80 == web3.eth.getBalance(policy_manager.address)
assert client_balance - (2 * value + 80) == web3.eth.getBalance(client)
assert 2 * value + 90 + rate == web3.eth.getBalance(policy_manager.address)
assert client_balance - (2 * value + 90 + rate) == web3.eth.getBalance(client)
assert 0 == web3.toInt(
policy_manager.call().getPolicyInfo(DISABLED_FIELD, policy_id_2, NULL_ADDR))
@ -508,8 +620,8 @@ def test_refund(web3, chain, escrow, policy_manager):
# But can refund others
tx = policy_manager.transact({'from': client, 'gas_price': 0}).refund(policy_id_2)
chain.wait_for_receipt(tx)
assert 3 * 80 == web3.eth.getBalance(policy_manager.address)
assert client_balance - 3 * 80 == web3.eth.getBalance(client)
assert 3 * 90 == web3.eth.getBalance(policy_manager.address)
assert client_balance - 3 * 90 == web3.eth.getBalance(client)
assert 1 == web3.toInt(
policy_manager.call().getPolicyInfo(DISABLED_FIELD, policy_id_2, NULL_ADDR))
@ -537,13 +649,13 @@ def test_refund(web3, chain, escrow, policy_manager):
# Create policy again
period = escrow.call().getCurrentPeriod()
tx = policy_manager.transact({'from': client, 'value': value, 'gas_price': 0})\
.createPolicy(policy_id_3, number_of_periods, [node1])
tx = policy_manager.transact({'from': client, 'value': int(value + 0.5 * rate), 'gas_price': 0})\
.createPolicy(policy_id_3, number_of_periods, int(0.5 * rate), [node1])
chain.wait_for_receipt(tx)
# Mint some periods
period += 1
tx = escrow.transact().pushDowntimePeriod(period, period)
tx = escrow.transact().pushDowntimePeriod(period - 1, period)
chain.wait_for_receipt(tx)
for x in range(3):
period += 1
@ -551,14 +663,14 @@ def test_refund(web3, chain, escrow, policy_manager):
chain.wait_for_receipt(tx)
tx = escrow.transact().setLastActivePeriod(period)
chain.wait_for_receipt(tx)
assert 140 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node1, 0))
assert 150 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node1, 0))
# Client revokes policy
wait_time(chain, 4)
tx = policy_manager.transact({'from': client, 'gas_price': 0}).revokePolicy(policy_id_3)
chain.wait_for_receipt(tx)
assert 60 + 3 * 80 == web3.eth.getBalance(policy_manager.address)
assert client_balance - (60 + 3 * 80) == web3.eth.getBalance(client)
assert 60 + 3 * 90 == web3.eth.getBalance(policy_manager.address)
assert client_balance - (60 + 3 * 90) == web3.eth.getBalance(client)
assert 1 == web3.toInt(
policy_manager.call().getPolicyInfo(DISABLED_FIELD, policy_id_3, NULL_ADDR))
@ -573,21 +685,21 @@ def test_refund(web3, chain, escrow, policy_manager):
assert policy_id_3 == event_args['policyId']
assert client == event_args['client']
assert node1 == event_args['node']
assert 140 == event_args['value']
assert 150 == event_args['value']
events = policy_revoked_log.get_all_entries()
assert 1 == len(events)
event_args = events[0]['args']
assert policy_id_3 == event_args['policyId']
assert client == event_args['client']
assert 140 == event_args['value']
assert 150 == event_args['value']
# Minting is useless after revoke
for x in range(20):
period += 1
tx = escrow.transact({'from': node1}).mint(period, 1)
chain.wait_for_receipt(tx)
assert 140 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node1, 0))
assert 150 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node1, 0))
events = policy_created_log.get_all_entries()
assert 3 == len(events)
@ -641,3 +753,4 @@ def test_verifying_state(web3, chain):
with pytest.raises(TransactionFailed):
tx = dispatcher.transact({'from': creator}).upgrade(contract_library_bad.address)
chain.wait_for_receipt(tx)