From b1d8ae98166d3961edcb4c4165ac787f27f75bab Mon Sep 17 00:00:00 2001 From: szotov Date: Wed, 11 Apr 2018 16:55:04 +0300 Subject: [PATCH] Added payment for the first/current period when creating a policy --- .../sol/source/contracts/PolicyManager.sol | 79 ++++--- .../eth/contracts/test_integration.py | 24 +- .../eth/contracts/test_policy_manager.py | 211 ++++++++++++++---- 3 files changed, 227 insertions(+), 87 deletions(-) diff --git a/nkms/blockchain/eth/sol/source/contracts/PolicyManager.sol b/nkms/blockchain/eth/sol/source/contracts/PolicyManager.sol index 9b0242eca..8512d4152 100644 --- a/nkms/blockchain/eth/sol/source/contracts/PolicyManager.sol +++ b/nkms/blockchain/eth/sol/source/contracts/PolicyManager.sol @@ -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; diff --git a/tests/blockchain/eth/contracts/test_integration.py b/tests/blockchain/eth/contracts/test_integration.py index 968138235..035900e6b 100644 --- a/tests/blockchain/eth/contracts/test_integration.py +++ b/tests/blockchain/eth/contracts/test_integration.py @@ -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)) diff --git a/tests/blockchain/eth/contracts/test_policy_manager.py b/tests/blockchain/eth/contracts/test_policy_manager.py index 02b815317..f18f2593d 100644 --- a/tests/blockchain/eth/contracts/test_policy_manager.py +++ b/tests/blockchain/eth/contracts/test_policy_manager.py @@ -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) +