[KMS-ETH]- Merge branch 'master' into upgradeable-contracts

pull/195/head^2
szotov 2018-03-17 18:23:33 +03:00
commit 270ab83565
6 changed files with 708 additions and 207 deletions

View File

@ -233,7 +233,7 @@ contract MinersEscrow is Issuer, Ownable {
internal view returns (uint256)
{
MinerInfo storage info = minerInfo[_owner];
return _lockedTokens.divCeil(info.releaseRate).sub(1);
return _lockedTokens.divCeil(info.releaseRate).sub(uint(1));
}
/**
@ -447,7 +447,7 @@ contract MinersEscrow is Issuer, Ownable {
* @notice Mint tokens for sender for previous periods if he locked his tokens and confirmed activity
**/
function mint() external onlyTokenOwner {
uint256 previousPeriod = getCurrentPeriod().sub(1);
uint256 previousPeriod = getCurrentPeriod().sub(uint(1));
MinerInfo storage info = minerInfo[msg.sender];
uint256 numberPeriodsForMinting = info.numberConfirmedPeriods;
require(numberPeriodsForMinting > 0 &&

View File

@ -4,6 +4,7 @@ pragma solidity ^0.4.18;
import "./zeppelin/token/ERC20/SafeERC20.sol";
import "./zeppelin/math/SafeMath.sol";
import "./zeppelin/math/Math.sol";
import "./lib/AdditionalMath.sol";
import "./MinersEscrow.sol";
import "./NuCypherKMSToken.sol";
import "./proxy/Upgradeable.sol";
@ -15,38 +16,61 @@ import "./proxy/Upgradeable.sol";
contract PolicyManager is Upgradeable {
using SafeERC20 for NuCypherKMSToken;
using SafeMath for uint256;
using AdditionalMath for uint256;
using AdditionalMath for int256;
event PolicyCreated(
bytes20 indexed policyId,
address indexed client,
address indexed node
address[] indexed nodes
);
event PolicyRevoked(
bytes20 indexed policyId,
address indexed client,
uint256 value
);
event ArrangementRevoked(
bytes20 indexed policyId,
address indexed client,
address indexed node,
uint256 value
);
event PolicyRevoked(bytes20 indexed policyId);
event Withdrawn(address indexed node, uint256 value);
event Refunded(
event RefundForArrangement(
bytes20 indexed policyId,
address indexed client,
address indexed node,
uint256 value
);
event RefundForPolicy(
bytes20 indexed policyId,
address indexed client,
uint256 value
);
// enum PolicyState { Pending, Active }
// enum PolicyType { Periods }
struct ArrangementInfo {
uint256 indexOfDowntimePeriods;
uint256 lastRefundedPeriod;
bool disabled;
}
struct Policy {
address client;
address node;
// PolicyState state;
mapping(address => ArrangementInfo) arrangements;
address[] nodes;
// policy for activity periods
uint256 rate;
uint256 startPeriod;
uint256 lastPeriod;
uint256 indexOfDowntimePeriods;
bool disabled;
}
struct NodeInfo {
uint256 reward;
mapping (uint256 => uint256) rewardByPeriod;
uint256 lastRewardByPeriod;
uint256 lastMinedPeriod;
mapping (uint256 => int256) rewardChanges;
}
bytes20 constant RESERVED_POLICY_ID = bytes20(0);
@ -73,53 +97,51 @@ contract PolicyManager is Upgradeable {
* @notice Create policy by client
* @dev Generate policy id before creation
* @param _policyId Policy id
* @param _node Node that will handle policy
* @param _numberOfPeriods Duration of the policy in periods
* @param _nodes Nodes that will handle policy
**/
function createPolicy(
bytes20 _policyId,
address _node,
uint256 _numberOfPeriods
uint256 _numberOfPeriods,
address[] _nodes
)
public payable
{
require(
policies[_policyId].rate == 0 &&
_node != RESERVED_NODE &&
_numberOfPeriods != 0 &&
escrow.getLockedTokens(_node) != 0 &&
msg.value > 0 &&
msg.value % _numberOfPeriods == 0 &&
msg.value % _numberOfPeriods % _nodes.length == 0 &&
_policyId != RESERVED_POLICY_ID
);
Policy storage policy = policies[_policyId];
policy.client = msg.sender;
policy.node = _node;
// policy.state = PolicyState.Pending;
policy.nodes = _nodes;
uint256 currentPeriod = escrow.getCurrentPeriod();
policy.startPeriod = currentPeriod.add(1);
policy.startPeriod = currentPeriod.add(uint(1));
policy.lastPeriod = currentPeriod.add(_numberOfPeriods);
uint256 feeByPeriod = msg.value.div(_numberOfPeriods);
uint256 feeByPeriod = msg.value.div(_numberOfPeriods).div(_nodes.length);
policy.rate = feeByPeriod;
uint256 endPeriod = policy.lastPeriod.add(uint(1));
NodeInfo storage node = nodes[_node];
for (uint256 i = policy.startPeriod; i <= policy.lastPeriod; i++) {
node.rewardByPeriod[i] = node.rewardByPeriod[i].add(feeByPeriod);
policy.nodes = _nodes;
for (uint256 i = 0; i < _nodes.length; i++) {
require(escrow.getLockedTokens(_nodes[i]) != 0 &&
_nodes[i] != RESERVED_NODE);
NodeInfo storage node = nodes[_nodes[i]];
node.rewardChanges[policy.startPeriod] = node.rewardChanges[policy.startPeriod]
.add(feeByPeriod);
node.rewardChanges[endPeriod] = node.rewardChanges[endPeriod].sub(feeByPeriod);
// TODO node should pay for this
if (node.lastMinedPeriod == 0) {
node.lastMinedPeriod = currentPeriod;
}
ArrangementInfo storage arrangement = policy.arrangements[_nodes[i]];
arrangement.indexOfDowntimePeriods = escrow.getDowntimePeriodsLength(_nodes[i]);
}
policy.indexOfDowntimePeriods = escrow.getDowntimePeriodsLength(_node);
PolicyCreated(_policyId, msg.sender, _node);
}
// /**
// * @notice Confirm policy by node
// * @param _policyId Policy id
// **/
// function confirmPolicy(bytes20 _policyId) public {
// Policy policy = policies[_policyId];
// require(policy.state == PolicyState.Pending &&
// policy.node == msg.sender);
// policy.state = PolicyState.Active;
// }
PolicyCreated(_policyId, msg.sender, _nodes);
}
/**
* @notice Update node reward
@ -129,8 +151,15 @@ contract PolicyManager is Upgradeable {
function updateReward(address _node, uint256 _period) external {
require(msg.sender == address(escrow));
NodeInfo storage node = nodes[_node];
node.reward = node.reward.add(node.rewardByPeriod[_period]);
delete node.rewardByPeriod[_period];
if (node.lastMinedPeriod == 0) {
return;
}
for (uint256 i = node.lastMinedPeriod + 1; i <= _period; i++) {
node.lastRewardByPeriod = node.lastRewardByPeriod.add(node.rewardChanges[i]);
// delete node.rewardChanges[i];
}
node.lastMinedPeriod = _period;
node.reward = node.reward.add(node.lastRewardByPeriod);
}
/**
@ -151,19 +180,63 @@ contract PolicyManager is Upgradeable {
**/
function revokePolicy(bytes20 _policyId) public {
Policy storage policy = policies[_policyId];
require(policy.client == msg.sender);
uint256 refund = calculateRefund(_policyId);
NodeInfo storage node = nodes[policy.node];
for (uint256 i = policy.startPeriod; i <= policy.lastPeriod; i++) {
node.rewardByPeriod[i] = node.rewardByPeriod[i].sub(policy.rate);
refund = refund.add(policy.rate);
require(policy.client == msg.sender && !policy.disabled);
uint256 refundValue = 0;
uint256 endPeriod = policy.lastPeriod.add(uint(1));
for (uint256 i = 0; i < policy.nodes.length; i++) {
address node = policy.nodes[i];
if (policy.arrangements[node].disabled) {
continue;
}
uint256 nodeRefundValue = revokeArrangement(policy, node, endPeriod);
refundValue = refundValue.add(nodeRefundValue);
ArrangementRevoked(_policyId, msg.sender, node, nodeRefundValue);
}
delete policies[_policyId];
if (refund > 0) {
msg.sender.transfer(refund);
Refunded(_policyId, msg.sender, refund);
policy.disabled = true;
if (refundValue > 0) {
msg.sender.transfer(refundValue);
}
PolicyRevoked(_policyId);
PolicyRevoked(_policyId, msg.sender, refundValue);
}
/**
* @notice Revoke arrangement by client
* @param _policyId Policy id
* @param _node Node that will be excluded
**/
function revokeArrangement(bytes20 _policyId, address _node)
public returns (uint256 refundValue)
{
Policy storage policy = policies[_policyId];
require(policy.client == msg.sender &&
!policy.disabled &&
!policy.arrangements[_node].disabled);
uint256 endPeriod = policy.lastPeriod.add(uint(1));
refundValue = revokeArrangement(policy, _node, endPeriod);
if (refundValue > 0) {
msg.sender.transfer(refundValue);
}
ArrangementRevoked(_policyId, msg.sender, _node, refundValue);
}
/**
* @notice Revoke arrangement by client
* @param _policy Policy
* @param _node Node that will be excluded
* @param _endPeriod Pre-calculated end of period value
**/
function revokeArrangement(Policy storage _policy, address _node, uint256 _endPeriod)
internal returns (uint256 refundValue)
{
refundValue = calculateRefund(_policy, _node);
NodeInfo storage node = nodes[_node];
ArrangementInfo storage arrangement = _policy.arrangements[_node];
node.rewardChanges[arrangement.lastRefundedPeriod] =
node.rewardChanges[arrangement.lastRefundedPeriod].sub(_policy.rate);
node.rewardChanges[_endPeriod] = node.rewardChanges[_endPeriod].add(_policy.rate);
refundValue = refundValue.add(
_endPeriod.sub(arrangement.lastRefundedPeriod).mul(_policy.rate));
_policy.arrangements[_node].disabled = true;
}
/**
@ -172,79 +245,139 @@ contract PolicyManager is Upgradeable {
**/
function refund(bytes20 _policyId) public {
Policy storage policy = policies[_policyId];
// require(policy.state == PolicyState.Active &&
// msg.sender == policy.client);
require(msg.sender == policy.client);
uint256 refundValue = calculateRefund(_policyId);
address client = policy.client;
if (policy.startPeriod > policy.lastPeriod) {
delete policies[_policyId];
require(msg.sender == policy.client && !policy.disabled);
uint256 refundValue = 0;
uint256 numberOfActive = policy.nodes.length;
for (uint256 i = 0; i < policy.nodes.length; i++) {
address node = policy.nodes[i];
if (policy.arrangements[node].disabled) {
numberOfActive--;
continue;
}
uint256 nodeRefundValue = calculateRefund(policy, node);
if (policy.arrangements[node].lastRefundedPeriod > policy.lastPeriod) {
policy.arrangements[node].disabled = true;
numberOfActive--;
}
refundValue = refundValue.add(nodeRefundValue);
RefundForArrangement(_policyId, msg.sender, node, nodeRefundValue);
}
if (refundValue > 0) {
client.transfer(refundValue);
Refunded(_policyId, client, refundValue);
msg.sender.transfer(refundValue);
}
if (numberOfActive == 0) {
policy.disabled = true;
}
RefundForPolicy(_policyId, msg.sender, refundValue);
}
/**
* @notice Refund part of one node's fee by client
* @param _policyId Policy id
* @param _node Node address
**/
function refund(bytes20 _policyId, address _node)
public returns (uint256 refundValue)
{
Policy storage policy = policies[_policyId];
require(msg.sender == policy.client &&
!policy.disabled &&
!policy.arrangements[_node].disabled);
refundValue = calculateRefund(policy, _node);
if (policy.arrangements[_node].lastRefundedPeriod > policy.lastPeriod) {
policy.arrangements[_node].disabled = true;
}
if (refundValue > 0) {
msg.sender.transfer(refundValue);
}
RefundForArrangement(_policyId, msg.sender, _node, refundValue);
}
/**
* @notice Calculate amount of refund
* @param _policyId Policy id
* @param _policy Policy
* @param _node Node for calculation
**/
//TODO extract checkRefund method
function calculateRefund(bytes20 _policyId) internal returns (uint256) {
Policy storage policy = policies[_policyId];
uint256 currentPeriod = escrow.getCurrentPeriod();
uint256 maxPeriod = Math.min256(currentPeriod, policy.lastPeriod);
uint256 minPeriod = policy.startPeriod;
function calculateRefund(Policy storage _policy, address _node) internal returns (uint256) {
ArrangementInfo storage arrangement = _policy.arrangements[_node];
uint256 maxPeriod = Math.min256(escrow.getCurrentPeriod(), _policy.lastPeriod);
uint256 minPeriod = Math.max256(_policy.startPeriod, arrangement.lastRefundedPeriod);
uint256 downtimePeriods = 0;
uint256 length = escrow.getDowntimePeriodsLength(policy.node);
for (uint256 i = policy.indexOfDowntimePeriods; i < length; i++) {
uint256 length = escrow.getDowntimePeriodsLength(_node);
for (uint256 i = arrangement.indexOfDowntimePeriods; i < length; i++) {
uint256 startPeriod;
uint256 endPeriod;
(startPeriod, endPeriod) = escrow.getDowntimePeriods(policy.node, i);
(startPeriod, endPeriod) = escrow.getDowntimePeriods(_node, i);
if (startPeriod > maxPeriod) {
break;
} else if (endPeriod < minPeriod) {
continue;
}
uint256 max = Math.min256(maxPeriod, endPeriod);
uint256 min = Math.max256(minPeriod, startPeriod);
downtimePeriods = downtimePeriods.add(max.sub(min).add(1));
downtimePeriods = downtimePeriods.add(
Math.min256(maxPeriod, endPeriod)
.sub(Math.max256(minPeriod, startPeriod))
.add(uint(1)));
if (maxPeriod <= endPeriod) {
break;
}
}
policy.indexOfDowntimePeriods = i;
uint256 lastActivePeriod = escrow.getLastActivePeriod(policy.node);
arrangement.indexOfDowntimePeriods = i;
uint256 lastActivePeriod = escrow.getLastActivePeriod(_node);
if (i == length && lastActivePeriod < maxPeriod) {
min = Math.max256(minPeriod.sub(1), lastActivePeriod);
downtimePeriods = downtimePeriods.add(maxPeriod.sub(min));
downtimePeriods = downtimePeriods.add(
maxPeriod.sub(Math.max256(
minPeriod.sub(uint(1)), lastActivePeriod)));
}
policy.startPeriod = maxPeriod.add(1);
arrangement.lastRefundedPeriod = maxPeriod.add(uint(1));
return policy.rate.mul(downtimePeriods);
return _policy.rate.mul(downtimePeriods);
}
/**
* @notice Get number of nodes in policy
* @param _policyId Policy id
**/
function getPolicyNodesLength(bytes20 _policyId)
public view returns (uint256)
{
return policies[_policyId].nodes.length;
}
/**
* @notice Get node from policy
* @param _policyId Policy id
* @param _index Index of node
**/
function getPolicyNode(bytes20 _policyId, uint256 _index)
public view returns (address)
{
return policies[_policyId].nodes[_index];
}
/**
* @dev Used only in verifyState(address) method
**/
function getPolicyField(bytes20 _policyId, uint8 _field)
function getPolicyField(bytes20 _policyId, uint8 _field, address _node)
public view returns (bytes32)
{
Policy storage policy = policies[_policyId];
if (_field == 0) {
return bytes32(policy.client);
} else if (_field == 1) {
return bytes32(policy.node);
} else if (_field == 2) {
return bytes32(policy.rate);
} else if (_field == 3) {
} else if (_field == 2) {
return bytes32(policy.startPeriod);
} else if (_field == 4) {
} else if (_field == 3) {
return bytes32(policy.lastPeriod);
} else if (_field == 4) {
return policy.disabled ? bytes32(1) : bytes32(0);
} else if (_field == 5) {
return bytes32(policy.indexOfDowntimePeriods);
return bytes32(policy.arrangements[_node].indexOfDowntimePeriods);
} else if (_field == 6) {
return bytes32(policy.arrangements[_node].lastRefundedPeriod);
} else if (_field == 7) {
return policy.arrangements[_node].disabled ? bytes32(1) : bytes32(0);
}
}
@ -252,38 +385,55 @@ contract PolicyManager is Upgradeable {
* @dev Used only in verifyState(address) method
**/
function getNodeInfoField(address _node, uint8 _field, uint256 _period)
public view returns (uint256)
public view returns (bytes32)
{
NodeInfo storage nodeInfo = nodes[_node];
if (_field == 0) {
return nodeInfo.reward;
return bytes32(nodeInfo.reward);
} else if (_field == 1) {
return nodeInfo.rewardByPeriod[_period];
return bytes32(nodeInfo.lastRewardByPeriod);
} else if (_field == 2) {
return bytes32(nodeInfo.lastMinedPeriod);
} else if (_field == 3) {
return bytes32(nodeInfo.rewardChanges[_period]);
}
}
function verifyState(address _testTarget) public onlyOwner {
require(address(delegateGet(_testTarget, "escrow()")) == address(escrow));
Policy storage policy = policies[RESERVED_POLICY_ID];
require(address(delegateGet(_testTarget, "getPolicyField(bytes20,uint8)",
RESERVED_POLICY_ID, 0)) == policy.client);
require(address(delegateGet(_testTarget, "getPolicyField(bytes20,uint8)",
RESERVED_POLICY_ID, 1)) == policy.node);
require(uint256(delegateGet(_testTarget, "getPolicyField(bytes20,uint8)",
RESERVED_POLICY_ID, 2)) == policy.rate);
require(uint256(delegateGet(_testTarget, "getPolicyField(bytes20,uint8)",
RESERVED_POLICY_ID, 3)) == policy.startPeriod);
require(uint256(delegateGet(_testTarget, "getPolicyField(bytes20,uint8)",
RESERVED_POLICY_ID, 4)) == policy.lastPeriod);
require(uint256(delegateGet(_testTarget, "getPolicyField(bytes20,uint8)",
RESERVED_POLICY_ID, 5)) == policy.indexOfDowntimePeriods);
require(address(delegateGet(_testTarget, "getPolicyField(bytes20,uint8,address)",
RESERVED_POLICY_ID, 0, 0x0)) == policy.client);
require(uint256(delegateGet(_testTarget, "getPolicyField(bytes20,uint8,address)",
RESERVED_POLICY_ID, 1, 0x0)) == policy.rate);
require(uint256(delegateGet(_testTarget, "getPolicyField(bytes20,uint8,address)",
RESERVED_POLICY_ID, 2, 0x0)) == policy.startPeriod);
require(uint256(delegateGet(_testTarget, "getPolicyField(bytes20,uint8,address)",
RESERVED_POLICY_ID, 3, 0x0)) == policy.lastPeriod);
require((delegateGet(_testTarget, "getPolicyField(bytes20,uint8,address)",
RESERVED_POLICY_ID, 4, 0x0) == bytes32(1)) == policy.disabled);
require(uint256(delegateGet(_testTarget, "getPolicyField(bytes20,uint8,address)",
RESERVED_POLICY_ID, 5, bytes32(RESERVED_NODE))) ==
policy.arrangements[RESERVED_NODE].indexOfDowntimePeriods);
require(uint256(delegateGet(_testTarget, "getPolicyField(bytes20,uint8,address)",
RESERVED_POLICY_ID, 6, bytes32(RESERVED_NODE))) ==
policy.arrangements[RESERVED_NODE].lastRefundedPeriod);
require((delegateGet(_testTarget, "getPolicyField(bytes20,uint8,address)",
RESERVED_POLICY_ID, 7, bytes32(RESERVED_NODE)) == bytes32(1)) ==
policy.arrangements[RESERVED_NODE].disabled);
require(uint256(delegateGet(_testTarget, "getPolicyNodesLength(bytes20)",
RESERVED_POLICY_ID)) == policy.nodes.length);
require(address(delegateGet(_testTarget, "getPolicyNode(bytes20,uint256)",
RESERVED_POLICY_ID, 0)) == policy.nodes[0]);
NodeInfo storage nodeInfo = nodes[RESERVED_NODE];
require(uint256(delegateGet(_testTarget, "getNodeInfoField(address,uint8,uint256)",
bytes32(RESERVED_NODE), 0, 0)) == nodeInfo.reward);
require(uint256(delegateGet(_testTarget, "getNodeInfoField(address,uint8,uint256)",
bytes32(RESERVED_NODE), 1, 22)) == nodeInfo.rewardByPeriod[22]);
bytes32(RESERVED_NODE), 1, 0)) == nodeInfo.lastRewardByPeriod);
require(uint256(delegateGet(_testTarget, "getNodeInfoField(address,uint8,uint256)",
bytes32(RESERVED_NODE), 1, 44)) == nodeInfo.rewardByPeriod[44]);
bytes32(RESERVED_NODE), 2, 0)) == nodeInfo.lastMinedPeriod);
require(int256(delegateGet(_testTarget, "getNodeInfoField(address,uint8,uint256)",
bytes32(RESERVED_NODE), 3, 11)) == nodeInfo.rewardChanges[11]);
}
function finishUpgrade(address _target) public onlyOwner {
@ -292,15 +442,18 @@ contract PolicyManager is Upgradeable {
// Create fake Policy and NodeInfo to use them in verifyState(address)
Policy storage policy = policies[RESERVED_POLICY_ID];
policy.client = owner;
policy.node = owner;
policy.startPeriod = 1;
policy.lastPeriod = 2;
policy.rate = 3;
policy.indexOfDowntimePeriods = 4;
policy.disabled = true;
policy.nodes.push(RESERVED_NODE);
policy.arrangements[RESERVED_NODE].indexOfDowntimePeriods = 11;
policy.arrangements[RESERVED_NODE].lastRefundedPeriod = 22;
policy.arrangements[RESERVED_NODE].disabled = true;
NodeInfo storage nodeInfo = nodes[RESERVED_NODE];
nodeInfo.reward = 100;
nodeInfo.rewardByPeriod[22] = 33;
nodeInfo.rewardByPeriod[44] = 55;
nodeInfo.lastRewardByPeriod = 33;
nodeInfo.lastMinedPeriod = 44;
nodeInfo.rewardChanges[11] = 55;
}
}
}

View File

@ -17,4 +17,44 @@ library AdditionalMath {
return (a.add(b) - 1) / b;
}
/**
* @dev Adds unsigned value to signed value, throws on overflow.
*/
function add(int256 a, uint256 b) internal pure returns (int256) {
int256 c = a + int256(b);
assert(c >= a);
return c;
}
/**
* @dev Subtracts two numbers, throws on overflow.
*/
function sub(int256 a, uint256 b) internal pure returns (int256) {
int256 c = a - int256(b);
assert(c <= a);
return c;
}
/**
* @dev Adds signed value to unsigned value, throws on overflow.
*/
function add(uint256 a, int256 b) internal pure returns (uint256) {
if (b >= 0) {
return a.add(uint256(b));
} else {
return a.sub(uint256(-b));
}
}
/**
* @dev Subtracts signed value from unsigned value, throws on overflow.
*/
function sub(uint256 a, int256 b) internal pure returns (uint256) {
if (b >= 0) {
return a.sub(uint256(b));
} else {
return a.add(uint256(-b));
}
}
}

View File

@ -7,12 +7,13 @@ A simple Python script to deploy contracts and then estimate gas for different m
from nkms_eth.blockchain import TesterBlockchain
from nkms_eth.escrow import Escrow
from nkms_eth.token import NuCypherKMSToken
import os
def main():
testerchain = TesterBlockchain()
chain, web3 = testerchain._chain, testerchain._chain.web3
creator, ursula1, ursula2, ursula3, *everyone_else = web3.eth.accounts
creator, ursula1, ursula2, ursula3, alice1, *everyone_else = web3.eth.accounts
print("Web3 providers are", web3.providers)
@ -37,7 +38,7 @@ def main():
# Pre deposit tokens
tx = token.transact({'from': creator}).approve(escrow.contract.address, 10 ** 7)
chain.wait.for_receipt(tx)
print("Pre-deposit tokens fro 5 owners = " +
print("Pre-deposit tokens for 5 owners = " +
str(escrow.contract.estimateGas({'from': creator}).preDeposit(
web3.eth.accounts[4:9], [10 ** 6] * 5, [1] * 5)))
@ -179,6 +180,109 @@ def main():
tx = escrow.transact({'from': ursula3}).mint()
chain.wait.for_receipt(tx)
# Create policy
policy_id_1 = os.urandom(20)
policy_id_2 = os.urandom(20)
number_of_periods = 10
print("First creating policy (1 node, 10 periods) = " +
str(policy_manager.estimateGas({'from': alice1, 'value': 10000})
.createPolicy(policy_id_1, number_of_periods, [ursula1])))
tx = policy_manager.transact({'from': alice1, 'value': 10000})\
.createPolicy(policy_id_1, number_of_periods, [ursula1])
chain.wait.for_receipt(tx)
print("Second creating policy (1 node, 10 periods) = " +
str(policy_manager.estimateGas({'from': alice1, 'value': 10000})
.createPolicy(policy_id_2, number_of_periods, [ursula1])))
tx = policy_manager.transact({'from': alice1, 'value': 10000}) \
.createPolicy(policy_id_2, number_of_periods, [ursula1])
chain.wait.for_receipt(tx)
# Revoke policy
print("Revoking policy = " +
str(policy_manager.estimateGas({'from': alice1}).revokePolicy(policy_id_1)))
tx = policy_manager.transact({'from': alice1}).revokePolicy(policy_id_1)
chain.wait.for_receipt(tx)
tx = policy_manager.transact({'from': alice1}).revokePolicy(policy_id_2)
chain.wait.for_receipt(tx)
# Create policy with more periods
policy_id_1 = os.urandom(20)
policy_id_2 = os.urandom(20)
policy_id_3 = os.urandom(20)
number_of_periods = 100
print("First creating policy (1 node, " + str(number_of_periods) + " periods) = " +
str(policy_manager.estimateGas({'from': alice1, 'value': 10000})
.createPolicy(policy_id_1, number_of_periods, [ursula2])))
tx = policy_manager.transact({'from': alice1, 'value': 10000})\
.createPolicy(policy_id_1, number_of_periods, [ursula2])
chain.wait.for_receipt(tx)
testerchain.wait_time(1)
print("Second creating policy (1 node, " + str(number_of_periods) + " periods) = " +
str(policy_manager.estimateGas({'from': alice1, 'value': 10000})
.createPolicy(policy_id_2, number_of_periods, [ursula2])))
tx = policy_manager.transact({'from': alice1, 'value': 10000}) \
.createPolicy(policy_id_2, number_of_periods, [ursula2])
chain.wait.for_receipt(tx)
print("Third creating policy (1 node, " + str(number_of_periods) + " periods) = " +
str(policy_manager.estimateGas({'from': alice1, 'value': 10000})
.createPolicy(policy_id_3, number_of_periods, [ursula1])))
tx = policy_manager.transact({'from': alice1, 'value': 10000}) \
.createPolicy(policy_id_3, number_of_periods, [ursula1])
chain.wait.for_receipt(tx)
# Mine and revoke policy
testerchain.wait_time(10)
tx = escrow.transact({'from': ursula2}).confirmActivity()
chain.wait.for_receipt(tx)
tx = escrow.transact({'from': ursula1}).confirmActivity()
chain.wait.for_receipt(tx)
testerchain.wait_time(1)
print("First mining after downtime = " + str(escrow.contract.estimateGas({'from': ursula1}).mint()))
tx = escrow.transact({'from': ursula1}).mint()
chain.wait.for_receipt(tx)
print("Second mining after downtime = " + str(escrow.contract.estimateGas({'from': ursula2}).mint()))
tx = escrow.transact({'from': ursula2}).mint()
chain.wait.for_receipt(tx)
testerchain.wait_time(10)
print("First revoking policy after downtime = " +
str(policy_manager.estimateGas({'from': alice1}).revokePolicy(policy_id_1)))
tx = policy_manager.transact({'from': alice1}).revokePolicy(policy_id_1)
chain.wait.for_receipt(tx)
print("Second revoking policy after downtime = " +
str(policy_manager.estimateGas({'from': alice1}).revokePolicy(policy_id_2)))
tx = policy_manager.transact({'from': alice1}).revokePolicy(policy_id_2)
chain.wait.for_receipt(tx)
print("Second revoking policy after downtime = " +
str(policy_manager.estimateGas({'from': alice1}).revokePolicy(policy_id_3)))
tx = policy_manager.transact({'from': alice1}).revokePolicy(policy_id_3)
chain.wait.for_receipt(tx)
# Create policy with multiple nodes
policy_id_1 = os.urandom(20)
policy_id_2 = os.urandom(20)
policy_id_3 = os.urandom(20)
number_of_periods = 100
print("First creating policy (3 nodes, 100 periods) = " +
str(policy_manager.estimateGas({'from': alice1, 'value': 30000})
.createPolicy(policy_id_1, number_of_periods, [ursula1, ursula2, ursula3])))
tx = policy_manager.transact({'from': alice1, 'value': 30000}) \
.createPolicy(policy_id_1, number_of_periods, [ursula1, ursula2, ursula3])
chain.wait.for_receipt(tx)
print("Second creating policy (3 nodes, 100 periods) = " +
str(policy_manager.estimateGas({'from': alice1, 'value': 10000})
.createPolicy(policy_id_2, number_of_periods, [ursula1, ursula2, ursula3])))
tx = policy_manager.transact({'from': alice1, 'value': 10000}) \
.createPolicy(policy_id_2, number_of_periods, [ursula1, ursula2, ursula3])
chain.wait.for_receipt(tx)
print("Third creating policy (2 nodes, 100 periods) = " +
str(policy_manager.estimateGas({'from': alice1, 'value': 20000})
.createPolicy(policy_id_3, number_of_periods, [ursula1, ursula2])))
tx = policy_manager.transact({'from': alice1, 'value': 20000}) \
.createPolicy(policy_id_3, number_of_periods, [ursula1, ursula2])
chain.wait.for_receipt(tx)
print("All done!")

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.18;
import "contracts/PolicyManager.sol";
@ -16,16 +16,18 @@ contract MinersEscrowForPolicyMock {
PolicyManager public policyManager;
uint256 public secondsPerPeriod;
address public node;
mapping(address => bool) public nodes;
uint256 public lastActivePeriod;
Downtime[] public downtime;
/**
* @param _node Address of node that allow to use policy manager
* @param _nodes Addresses of nodes that allow to use policy manager
* @param _minutesPerPeriod Size of period in minutes
**/
function MinersEscrowForPolicyMock(address _node, uint256 _minutesPerPeriod) public {
node = _node;
function MinersEscrowForPolicyMock(address[] _nodes, uint256 _minutesPerPeriod) public {
for (uint256 i = 0; i < _nodes.length; i++) {
nodes[_nodes[i]] = true;
}
secondsPerPeriod = _minutesPerPeriod * 1 minutes;
}
@ -35,7 +37,7 @@ contract MinersEscrowForPolicyMock {
function getLockedTokens(address _owner)
public view returns (uint256)
{
if (_owner == node) {
if (nodes[_owner]) {
return 1;
}
return 0;
@ -67,7 +69,7 @@ contract MinersEscrowForPolicyMock {
* @param _period Period for minting
**/
function mint(uint256 _period) external {
policyManager.updateReward(node, _period);
policyManager.updateReward(msg.sender, _period);
}
/**

View File

@ -6,10 +6,13 @@ import os
@pytest.fixture()
def escrow(web3, chain):
creator = web3.eth.accounts[0]
node = web3.eth.accounts[1]
node1 = web3.eth.accounts[3]
node2 = web3.eth.accounts[4]
node3 = web3.eth.accounts[5]
# Creator deploys the escrow
escrow, _ = chain.provider.get_or_deploy_contract(
'MinersEscrowForPolicyMock', deploy_args=[node, MINUTES_IN_PERIOD],
'MinersEscrowForPolicyMock',
deploy_args=[[node1, node2, node3], MINUTES_IN_PERIOD],
deploy_transaction={'from': creator})
return escrow
@ -17,7 +20,7 @@ def escrow(web3, chain):
@pytest.fixture()
def policy_manager(web3, chain, escrow):
creator = web3.eth.accounts[0]
client = web3.eth.accounts[2]
client = web3.eth.accounts[1]
# Creator deploys the policy manager
policy_manager, _ = chain.provider.get_or_deploy_contract(
@ -44,6 +47,7 @@ def wait_time(chain, wait_periods):
MINUTES_IN_PERIOD = 10
policy_id = os.urandom(20)
policy_id_2 = os.urandom(20)
policy_id_3 = os.urandom(20)
rate = 20
number_of_periods = 10
value = rate * number_of_periods
@ -51,35 +55,43 @@ value = rate * number_of_periods
def test_create_revoke(web3, chain, escrow, policy_manager):
creator = web3.eth.accounts[0]
node = web3.eth.accounts[1]
client = web3.eth.accounts[2]
bad_node = web3.eth.accounts[3]
client = web3.eth.accounts[1]
bad_node = web3.eth.accounts[2]
node1 = web3.eth.accounts[3]
node2 = web3.eth.accounts[4]
node3 = web3.eth.accounts[5]
client_balance = web3.eth.getBalance(client)
# Try create policy for bad node
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client, 'value': value})\
.createPolicy(policy_id, bad_node, 1)
.createPolicy(policy_id, 1, [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])
chain.wait.for_receipt(tx)
# Try create policy with no ETH
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client})\
.createPolicy(policy_id, node, 1)
.createPolicy(policy_id, 1, [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, node, number_of_periods)
.createPolicy(policy_id, number_of_periods, [node1])
chain.wait.for_receipt(tx)
policy = policy_manager.call().policies(policy_id)
assert 200 == web3.eth.getBalance(policy_manager.address)
assert client_balance - 200 == web3.eth.getBalance(client)
assert client == policy[0]
assert node == policy[1]
assert rate == policy[2]
assert period + 1 == policy[3]
assert period + 10 == policy[4]
assert rate == policy[1]
assert period + 1 == policy[2]
assert period + 10 == policy[3]
assert not policy[4]
assert 1 == policy_manager.call().getPolicyNodesLength(policy_id)
assert node1 == policy_manager.call().getPolicyNode(policy_id, 0)
events = policy_manager.pastEvents('PolicyCreated').get()
assert 1 == len(events)
@ -87,12 +99,12 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
# TODO change when v4 of web3.py is released
assert policy_id == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node.lower() == event_args['node'].lower()
# assert node.lower() == event_args['nodes'][0].lower()
# Try to create policy again
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client, 'value': value}) \
.createPolicy(policy_id, node, number_of_periods)
.createPolicy(policy_id, number_of_periods, [node1])
chain.wait.for_receipt(tx)
# Only client can revoke policy
@ -102,27 +114,46 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
tx = policy_manager.transact({'from': client, 'gas_price': 0}).revokePolicy(policy_id)
chain.wait.for_receipt(tx)
policy = policy_manager.call().policies(policy_id)
assert '0x' + '0' * 40 == policy[0]
assert policy[4]
events = policy_manager.pastEvents('PolicyRevoked').get()
assert 1 == len(events)
event_args = events[0]['args']
# TODO change when v4 of web3.py is released
assert policy_id == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert value == event_args['value']
events = policy_manager.pastEvents('ArrangementRevoked').get()
assert 1 == len(events)
event_args = events[0]['args']
# TODO change when v4 of web3.py is released
assert policy_id == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node1.lower() == event_args['node'].lower()
assert value == event_args['value']
# Can't revoke again
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client}).revokePolicy(policy_id)
chain.wait.for_receipt(tx)
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client}).revokeArrangement(policy_id, node1)
chain.wait.for_receipt(tx)
# Create another policy
period = escrow.call().getCurrentPeriod()
tx = policy_manager.transact({'from': client, 'value': value, 'gas_price': 0})\
.createPolicy(policy_id_2, node, number_of_periods)
tx = policy_manager.transact({'from': client, 'value': 3 * value, 'gas_price': 0})\
.createPolicy(policy_id_2, number_of_periods, [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)
policy = policy_manager.call().policies(policy_id_2)
assert 200 == web3.eth.getBalance(policy_manager.address)
assert client_balance - 200 == web3.eth.getBalance(client)
assert client == policy[0]
assert node == policy[1]
assert rate == policy[2]
assert period + 1 == policy[3]
assert period + 10 == policy[4]
assert rate == policy[1]
assert period + 1 == policy[2]
assert period + 10 == policy[3]
assert not policy[4]
# assert node.lower() == event_args['node'].lower()
events = policy_manager.pastEvents('PolicyCreated').get()
assert 2 == len(events)
@ -130,80 +161,148 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
# TODO change when v4 of web3.py is released
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node.lower() == event_args['node'].lower()
# assert node.lower() == event_args['node'].lower()
events = policy_manager.pastEvents('Refunded').get()
assert 1 == len(events)
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 not policy[4]
events = policy_manager.pastEvents('ArrangementRevoked').get()
assert 2 == len(events)
event_args = events[1]['args']
# TODO change when v4 of web3.py is released
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node1.lower() == event_args['node'].lower()
assert value == event_args['value']
# Can't revoke again
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client}).revokeArrangement(policy_id_2, node1)
chain.wait.for_receipt(tx)
tx = policy_manager.transact({'from': client, 'gas_price': 0}).revokePolicy(policy_id_2)
chain.wait.for_receipt(tx)
assert 0 == web3.eth.getBalance(policy_manager.address)
assert client_balance == web3.eth.getBalance(client)
assert not policy[4]
events = policy_manager.pastEvents('ArrangementRevoked').get()
assert 4 == len(events)
event_args = events[2]['args']
# TODO change when v4 of web3.py is released
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node2.lower() == event_args['node'].lower()
assert value == event_args['value']
event_args = events[3]['args']
# TODO change when v4 of web3.py is released
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node3.lower() == event_args['node'].lower()
assert value == event_args['value']
events = policy_manager.pastEvents('PolicyRevoked').get()
assert 2 == len(events)
event_args = events[1]['args']
# TODO change when v4 of web3.py is released
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert 2 * value == event_args['value']
# Can't revoke again
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client}).revokePolicy(policy_id_2)
chain.wait.for_receipt(tx)
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client}).revokeArrangement(policy_id_2, node1)
chain.wait.for_receipt(tx)
events = policy_manager.pastEvents('RefundForArrangement').get()
assert 0 == len(events)
events = policy_manager.pastEvents('RefundForPolicy').get()
assert 0 == len(events)
def test_reward(web3, chain, escrow, policy_manager):
node = web3.eth.accounts[1]
client = web3.eth.accounts[2]
node_balance = web3.eth.getBalance(node)
client = web3.eth.accounts[1]
node1 = web3.eth.accounts[3]
node2 = web3.eth.accounts[4]
node3 = web3.eth.accounts[5]
node_balance = web3.eth.getBalance(node1)
# Mint period without policies
period = escrow.call().getCurrentPeriod()
tx = escrow.transact({'from': node1, 'gas_price': 0}).mint(period)
chain.wait.for_receipt(tx)
assert 0 == policy_manager.call().nodes(node1)[0]
# Create policy
period = escrow.call().getCurrentPeriod()
tx = policy_manager.transact({'from': client, 'value': value})\
.createPolicy(policy_id, node, number_of_periods)
tx = policy_manager.transact({'from': client, 'value': 3 * value})\
.createPolicy(policy_id, number_of_periods, [node1, node2, node3])
chain.wait.for_receipt(tx)
# Nothing to withdraw
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': node}).withdraw()
tx = policy_manager.transact({'from': node1}).withdraw()
chain.wait.for_receipt(tx)
# Can't update reward directly
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': node}).updateReward(node, period + 1)
tx = policy_manager.transact({'from': node1}).updateReward(node1, period + 1)
chain.wait.for_receipt(tx)
# Mint some periods
for x in range(5):
tx = escrow.transact({'from': node, 'gas_price': 0}).mint(period)
tx = escrow.transact({'from': node1, 'gas_price': 0}).mint(period)
chain.wait.for_receipt(tx)
period += 1
assert 80 == policy_manager.call().nodes(node)
assert 80 == policy_manager.call().nodes(node1)[0]
# Withdraw
tx = policy_manager.transact({'from': node, 'gas_price': 0}).withdraw()
tx = policy_manager.transact({'from': node1, 'gas_price': 0}).withdraw()
chain.wait.for_receipt(tx)
assert node_balance + 80 == web3.eth.getBalance(node)
assert 120 == web3.eth.getBalance(policy_manager.address)
assert node_balance + 80 == web3.eth.getBalance(node1)
assert 120 + 2 * value == web3.eth.getBalance(policy_manager.address)
events = policy_manager.pastEvents('Withdrawn').get()
assert 1 == len(events)
event_args = events[0]['args']
assert node.lower() == event_args['node'].lower()
assert node1.lower() == event_args['node'].lower()
assert 80 == event_args['value']
# Mint more periods
for x in range(20):
tx = escrow.transact({'from': node, 'gas_price': 0}).mint(period)
tx = escrow.transact({'from': node1, 'gas_price': 0}).mint(period)
chain.wait.for_receipt(tx)
period += 1
assert 120 == policy_manager.call().nodes(node)
assert 120 == policy_manager.call().nodes(node1)[0]
# Withdraw
tx = policy_manager.transact({'from': node, 'gas_price': 0}).withdraw()
tx = policy_manager.transact({'from': node1, 'gas_price': 0}).withdraw()
chain.wait.for_receipt(tx)
assert node_balance + 200 == web3.eth.getBalance(node)
assert 0 == web3.eth.getBalance(policy_manager.address)
assert node_balance + value == web3.eth.getBalance(node1)
assert 2 * value == web3.eth.getBalance(policy_manager.address)
events = policy_manager.pastEvents('Withdrawn').get()
assert 2 == len(events)
event_args = events[1]['args']
assert node.lower() == event_args['node'].lower()
assert node1.lower() == event_args['node'].lower()
assert 120 == event_args['value']
def test_refund(web3, chain, escrow, policy_manager):
node = web3.eth.accounts[1]
client = web3.eth.accounts[2]
client = web3.eth.accounts[1]
node1 = web3.eth.accounts[3]
node2 = web3.eth.accounts[4]
node3 = web3.eth.accounts[5]
client_balance = web3.eth.getBalance(client)
# Create policy
tx = policy_manager.transact({'from': client, 'value': value, 'gas_price': 0}) \
.createPolicy(policy_id, node, number_of_periods)
.createPolicy(policy_id, number_of_periods, [node1])
chain.wait.for_receipt(tx)
tx = escrow.transact().setLastActivePeriod(escrow.call().getCurrentPeriod())
chain.wait.for_receipt(tx)
@ -216,7 +315,15 @@ def test_refund(web3, chain, escrow, policy_manager):
assert client_balance - 20 == web3.eth.getBalance(client)
assert client == policy_manager.call().policies(policy_id)[0]
events = policy_manager.pastEvents('Refunded').get()
events = policy_manager.pastEvents('RefundForArrangement').get()
assert 1 == len(events)
event_args = events[0]['args']
# TODO change when v4 of web3.py is released
assert policy_id == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node1.lower() == event_args['node'].lower()
assert 180 == event_args['value']
events = policy_manager.pastEvents('RefundForPolicy').get()
assert 1 == len(events)
event_args = events[0]['args']
# TODO change when v4 of web3.py is released
@ -229,9 +336,17 @@ def test_refund(web3, chain, escrow, policy_manager):
chain.wait.for_receipt(tx)
assert 0 == web3.eth.getBalance(policy_manager.address)
assert client_balance == web3.eth.getBalance(client)
assert '0x' + '0' * 40 == policy_manager.call().policies(policy_id)[0]
assert policy_manager.call().policies(policy_id)[4]
events = policy_manager.pastEvents('Refunded').get()
events = policy_manager.pastEvents('RefundForArrangement').get()
assert 2 == len(events)
event_args = events[1]['args']
# TODO change when v4 of web3.py is released
assert policy_id == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node1.lower() == event_args['node'].lower()
assert 20 == event_args['value']
events = policy_manager.pastEvents('RefundForPolicy').get()
assert 2 == len(events)
event_args = events[1]['args']
# TODO change when v4 of web3.py is released
@ -239,68 +354,145 @@ def test_refund(web3, chain, escrow, policy_manager):
assert client.lower() == event_args['client'].lower()
assert 20 == event_args['value']
# Can't refund again
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client}).refund(policy_id)
chain.wait.for_receipt(tx)
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client}).refund(policy_id, node1)
chain.wait.for_receipt(tx)
# Create policy again
period = escrow.call().getCurrentPeriod()
tx = policy_manager.transact({'from': client, 'value': value, 'gas_price': 0})\
.createPolicy(policy_id, node, number_of_periods)
tx = policy_manager.transact({'from': client, 'value': 3 * value, 'gas_price': 0})\
.createPolicy(policy_id_2, number_of_periods, [node1, node2, node3])
chain.wait.for_receipt(tx)
# Nothing to refund
tx = policy_manager.transact({'from': client, 'gas_price': 0}).refund(policy_id)
tx = policy_manager.transact({'from': client, 'gas_price': 0}).refund(policy_id_2)
chain.wait.for_receipt(tx)
assert 200 == web3.eth.getBalance(policy_manager.address)
assert client_balance - 200 == web3.eth.getBalance(client)
events = policy_manager.pastEvents('Refunded').get()
assert 2 == len(events)
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)
events = policy_manager.pastEvents('RefundForArrangement').get()
assert 6 == len(events)
event_args = events[2]['args']
# TODO change when v4 of web3.py is released
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node1.lower() == event_args['node'].lower()
assert 0 == event_args['value']
event_args = events[3]['args']
# TODO change when v4 of web3.py is released
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node2.lower() == event_args['node'].lower()
assert 0 == event_args['value']
event_args = events[4]['args']
# TODO change when v4 of web3.py is released
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node3.lower() == event_args['node'].lower()
assert 0 == event_args['value']
event_args = events[5]['args']
# TODO change when v4 of web3.py is released
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node1.lower() == event_args['node'].lower()
assert 0 == event_args['value']
events = policy_manager.pastEvents('RefundForPolicy').get()
assert 3 == len(events)
event_args = events[2]['args']
# TODO change when v4 of web3.py is released
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert 0 == event_args['value']
# Try to refund nonexistent policy
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client}).refund(policy_id_2)
tx = policy_manager.transact({'from': client}).refund(policy_id_3)
chain.wait.for_receipt(tx)
# Node try to refund by node
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': node}).refund(policy_id)
tx = policy_manager.transact({'from': node1}).refund(policy_id_2)
chain.wait.for_receipt(tx)
# Mint some periods and mark others as downtime periods
period += 1
tx = escrow.transact().mint(period)
tx = escrow.transact({'from': node1}).mint(period)
chain.wait.for_receipt(tx)
tx = escrow.transact().mint(period + 1)
tx = escrow.transact({'from': node1}).mint(period + 1)
chain.wait.for_receipt(tx)
tx = escrow.transact().pushDowntimePeriod(period + 2, period + 3)
chain.wait.for_receipt(tx)
tx = escrow.transact().mint(period + 4)
tx = escrow.transact({'from': node1}).mint(period + 4)
chain.wait.for_receipt(tx)
tx = escrow.transact().pushDowntimePeriod(period + 5, period + 7)
chain.wait.for_receipt(tx)
tx = escrow.transact().mint(period + 8)
tx = escrow.transact({'from': node1}).mint(period + 8)
chain.wait.for_receipt(tx)
tx = escrow.transact().setLastActivePeriod(period + 8)
chain.wait.for_receipt(tx)
assert 80 == policy_manager.call().nodes(node)
assert 80 == policy_manager.call().nodes(node1)[0]
# Wait and refund
wait_time(chain, 10)
tx = policy_manager.transact({'from': client, 'gas_price': 0}).refund(policy_id)
tx = policy_manager.transact({'from': client, 'gas_price': 0}).refund(policy_id_2, node1)
chain.wait.for_receipt(tx)
assert 80 == web3.eth.getBalance(policy_manager.address)
assert client_balance - 80 == web3.eth.getBalance(client)
assert '0x' + '0' * 40 == policy_manager.call().policies(policy_id)[0]
assert 2 * value + 80 == web3.eth.getBalance(policy_manager.address)
assert client_balance - (2 * value + 80) == web3.eth.getBalance(client)
assert not policy_manager.call().policies(policy_id_2)[4]
events = policy_manager.pastEvents('Refunded').get()
assert 3 == len(events)
event_args = events[2]['args']
events = policy_manager.pastEvents('RefundForArrangement').get()
assert 7 == len(events)
event_args = events[6]['args']
# TODO change when v4 of web3.py is released
assert policy_id == event_args['policyId'].encode('latin-1')
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node1.lower() == event_args['node'].lower()
assert 120 == event_args['value']
events = policy_manager.pastEvents('RefundForPolicy').get()
assert 3 == len(events)
# Can't refund arrangement again
with pytest.raises(TransactionFailed):
tx = policy_manager.transact({'from': client}).refund(policy_id, node1)
chain.wait.for_receipt(tx)
# 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 policy_manager.call().policies(policy_id_2)[4]
events = policy_manager.pastEvents('RefundForArrangement').get()
assert 9 == len(events)
event_args = events[7]['args']
# TODO change when v4 of web3.py is released
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node2.lower() == event_args['node'].lower()
assert 120 == event_args['value']
event_args = events[8]['args']
# TODO change when v4 of web3.py is released
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node3.lower() == event_args['node'].lower()
assert 120 == event_args['value']
events = policy_manager.pastEvents('RefundForPolicy').get()
assert 4 == len(events)
event_args = events[3]['args']
# TODO change when v4 of web3.py is released
assert policy_id_2 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert 2 * 120 == event_args['value']
# Create policy again
period = escrow.call().getCurrentPeriod()
tx = policy_manager.transact({'from': client, 'value': value, 'gas_price': 0})\
.createPolicy(policy_id, node, number_of_periods)
.createPolicy(policy_id_3, number_of_periods, [node1])
chain.wait.for_receipt(tx)
# Mint some periods
@ -309,37 +501,47 @@ def test_refund(web3, chain, escrow, policy_manager):
chain.wait.for_receipt(tx)
for x in range(3):
period += 1
tx = escrow.transact({'from': node}).mint(period)
tx = escrow.transact({'from': node1}).mint(period)
chain.wait.for_receipt(tx)
tx = escrow.transact().setLastActivePeriod(period)
chain.wait.for_receipt(tx)
assert 140 == policy_manager.call().nodes(node)
assert 140 == policy_manager.call().nodes(node1)[0]
# Client revokes policy
wait_time(chain, 4)
tx = policy_manager.transact({'from': client, 'gas_price': 0}).revokePolicy(policy_id)
tx = policy_manager.transact({'from': client, 'gas_price': 0}).revokePolicy(policy_id_3)
chain.wait.for_receipt(tx)
policy = policy_manager.call().policies(policy_id)
assert 140 == web3.eth.getBalance(policy_manager.address)
assert client_balance - 140 == web3.eth.getBalance(client)
assert '0x' + '0' * 40 == policy[0]
policy = policy_manager.call().policies(policy_id_3)
assert 60 + 3 * 80 == web3.eth.getBalance(policy_manager.address)
assert client_balance - (60 + 3 * 80) == web3.eth.getBalance(client)
assert policy[4]
events = policy_manager.pastEvents('Refunded').get()
events = policy_manager.pastEvents('RefundForArrangement').get()
assert 9 == len(events)
events = policy_manager.pastEvents('RefundForPolicy').get()
assert 4 == len(events)
event_args = events[3]['args']
events = policy_manager.pastEvents('ArrangementRevoked').get()
assert 1 == len(events)
event_args = events[0]['args']
# TODO change when v4 of web3.py is released
assert policy_id == event_args['policyId'].encode('latin-1')
assert policy_id_3 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert node1.lower() == event_args['node'].lower()
assert 140 == event_args['value']
events = policy_manager.pastEvents('PolicyRevoked').get()
assert 1 == len(events)
event_args = events[0]['args']
# TODO change when v4 of web3.py is released
assert policy_id_3 == event_args['policyId'].encode('latin-1')
assert client.lower() == event_args['client'].lower()
assert 140 == event_args['value']
# Minting is useless after revoke
for x in range(20):
period += 1
tx = escrow.transact({'from': node}).mint(period)
tx = escrow.transact({'from': node1}).mint(period)
chain.wait.for_receipt(tx)
assert 140 == policy_manager.call().nodes(node)
assert 140 == policy_manager.call().nodes(node1)[0]
events = policy_manager.pastEvents('PolicyCreated').get()
assert 3 == len(events)
events = policy_manager.pastEvents('PolicyRevoked').get()
assert 1 == len(events)