mirror of https://github.com/nucypher/nucypher.git
Merge pull request #2619 from vzotova/batch-policy
Creating multiple policies in one txpull/2672/head
commit
a71d1de553
|
@ -0,0 +1 @@
|
|||
PolicyManager: creating multiple policies in one tx
|
|
@ -17,7 +17,7 @@ import "contracts/proxy/Upgradeable.sol";
|
|||
/**
|
||||
* @title PolicyManager
|
||||
* @notice Contract holds policy data and locks accrued policy fees
|
||||
* @dev |v6.2.2|
|
||||
* @dev |v6.3.1|
|
||||
*/
|
||||
contract PolicyManager is Upgradeable {
|
||||
using SafeERC20 for NuCypherToken;
|
||||
|
@ -253,68 +253,161 @@ contract PolicyManager is Upgradeable {
|
|||
)
|
||||
external payable
|
||||
{
|
||||
Policy storage policy = policies[_policyId];
|
||||
require(
|
||||
_policyId != RESERVED_POLICY_ID &&
|
||||
policy.feeRate == 0 &&
|
||||
!policy.disabled &&
|
||||
_endTimestamp > block.timestamp &&
|
||||
msg.value > 0
|
||||
);
|
||||
|
||||
require(address(this).balance <= MAX_BALANCE);
|
||||
uint16 currentPeriod = getCurrentPeriod();
|
||||
uint16 endPeriod = uint16(_endTimestamp / secondsPerPeriod) + 1;
|
||||
uint256 numberOfPeriods = endPeriod - currentPeriod;
|
||||
|
||||
policy.sponsor = msg.sender;
|
||||
policy.startTimestamp = uint64(block.timestamp);
|
||||
policy.endTimestamp = _endTimestamp;
|
||||
policy.feeRate = uint128(msg.value.div(_nodes.length) / numberOfPeriods);
|
||||
require(policy.feeRate > 0 && policy.feeRate * numberOfPeriods * _nodes.length == msg.value);
|
||||
if (_policyOwner != msg.sender && _policyOwner != address(0)) {
|
||||
policy.owner = _policyOwner;
|
||||
}
|
||||
uint128 feeRate = uint128(msg.value.div(_nodes.length) / numberOfPeriods);
|
||||
require(feeRate > 0 && feeRate * numberOfPeriods * _nodes.length == msg.value);
|
||||
|
||||
Policy storage policy = createPolicy(_policyId, _policyOwner, _endTimestamp, feeRate, _nodes.length);
|
||||
|
||||
for (uint256 i = 0; i < _nodes.length; i++) {
|
||||
address node = _nodes[i];
|
||||
require(node != RESERVED_NODE);
|
||||
NodeInfo storage nodeInfo = nodes[node];
|
||||
require(nodeInfo.previousFeePeriod != 0 &&
|
||||
nodeInfo.previousFeePeriod < currentPeriod &&
|
||||
policy.feeRate >= getMinFeeRate(nodeInfo));
|
||||
// Check default value for feeDelta
|
||||
if (nodeInfo.feeDelta[currentPeriod] == DEFAULT_FEE_DELTA) {
|
||||
nodeInfo.feeDelta[currentPeriod] = int256(policy.feeRate);
|
||||
} else {
|
||||
// Overflow protection removed, because ETH total supply less than uint255/int256
|
||||
nodeInfo.feeDelta[currentPeriod] += int256(policy.feeRate);
|
||||
}
|
||||
if (nodeInfo.feeDelta[endPeriod] == DEFAULT_FEE_DELTA) {
|
||||
nodeInfo.feeDelta[endPeriod] = -int256(policy.feeRate);
|
||||
} else {
|
||||
nodeInfo.feeDelta[endPeriod] -= int256(policy.feeRate);
|
||||
}
|
||||
// Reset to default value if needed
|
||||
if (nodeInfo.feeDelta[currentPeriod] == 0) {
|
||||
nodeInfo.feeDelta[currentPeriod] = DEFAULT_FEE_DELTA;
|
||||
}
|
||||
if (nodeInfo.feeDelta[endPeriod] == 0) {
|
||||
nodeInfo.feeDelta[endPeriod] = DEFAULT_FEE_DELTA;
|
||||
}
|
||||
addFeeToNode(currentPeriod, endPeriod, node, feeRate, int256(feeRate));
|
||||
policy.arrangements.push(ArrangementInfo(node, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Create multiple policies with the same owner, nodes and length
|
||||
* @dev Generate policy ids before creation
|
||||
* @param _policyIds Policy ids
|
||||
* @param _policyOwner Policy owner. Zero address means sender is owner
|
||||
* @param _endTimestamp End timestamp of all policies in seconds
|
||||
* @param _nodes Nodes that will handle all policies
|
||||
*/
|
||||
function createPolicies(
|
||||
bytes16[] calldata _policyIds,
|
||||
address _policyOwner,
|
||||
uint64 _endTimestamp,
|
||||
address[] calldata _nodes
|
||||
)
|
||||
external payable
|
||||
{
|
||||
require(
|
||||
_endTimestamp > block.timestamp &&
|
||||
msg.value > 0 &&
|
||||
_policyIds.length > 1
|
||||
);
|
||||
|
||||
require(address(this).balance <= MAX_BALANCE);
|
||||
uint16 currentPeriod = getCurrentPeriod();
|
||||
uint16 endPeriod = uint16(_endTimestamp / secondsPerPeriod) + 1;
|
||||
uint256 numberOfPeriods = endPeriod - currentPeriod;
|
||||
|
||||
uint128 feeRate = uint128(msg.value.div(_nodes.length) / numberOfPeriods / _policyIds.length);
|
||||
require(feeRate > 0 && feeRate * numberOfPeriods * _nodes.length * _policyIds.length == msg.value);
|
||||
|
||||
for (uint256 i = 0; i < _policyIds.length; i++) {
|
||||
Policy storage policy = createPolicy(_policyIds[i], _policyOwner, _endTimestamp, feeRate, _nodes.length);
|
||||
|
||||
for (uint256 j = 0; j < _nodes.length; j++) {
|
||||
policy.arrangements.push(ArrangementInfo(_nodes[j], 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
int256 fee = int256(_policyIds.length * feeRate);
|
||||
|
||||
for (uint256 i = 0; i < _nodes.length; i++) {
|
||||
address node = _nodes[i];
|
||||
addFeeToNode(currentPeriod, endPeriod, node, feeRate, fee);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Create policy
|
||||
* @param _policyId Policy id
|
||||
* @param _policyOwner Policy owner. Zero address means sender is owner
|
||||
* @param _endTimestamp End timestamp of the policy in seconds
|
||||
* @param _feeRate Fee rate for policy
|
||||
* @param _nodesLength Number of nodes that will handle policy
|
||||
*/
|
||||
function createPolicy(
|
||||
bytes16 _policyId,
|
||||
address _policyOwner,
|
||||
uint64 _endTimestamp,
|
||||
uint128 _feeRate,
|
||||
uint256 _nodesLength
|
||||
)
|
||||
internal returns (Policy storage policy)
|
||||
{
|
||||
policy = policies[_policyId];
|
||||
require(
|
||||
_policyId != RESERVED_POLICY_ID &&
|
||||
policy.feeRate == 0 &&
|
||||
!policy.disabled
|
||||
);
|
||||
|
||||
policy.sponsor = msg.sender;
|
||||
policy.startTimestamp = uint64(block.timestamp);
|
||||
policy.endTimestamp = _endTimestamp;
|
||||
policy.feeRate = _feeRate;
|
||||
|
||||
if (_policyOwner != msg.sender && _policyOwner != address(0)) {
|
||||
policy.owner = _policyOwner;
|
||||
}
|
||||
|
||||
emit PolicyCreated(
|
||||
_policyId,
|
||||
msg.sender,
|
||||
_policyOwner == address(0) ? msg.sender : _policyOwner,
|
||||
policy.feeRate,
|
||||
_feeRate,
|
||||
policy.startTimestamp,
|
||||
policy.endTimestamp,
|
||||
_nodes.length
|
||||
_nodesLength
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Increase fee rate for specified node
|
||||
* @param _currentPeriod Current period
|
||||
* @param _endPeriod End period of policy
|
||||
* @param _node Node that will handle policy
|
||||
* @param _feeRate Fee rate for one policy
|
||||
* @param _overallFeeRate Fee rate for all policies
|
||||
*/
|
||||
function addFeeToNode(
|
||||
uint16 _currentPeriod,
|
||||
uint16 _endPeriod,
|
||||
address _node,
|
||||
uint128 _feeRate,
|
||||
int256 _overallFeeRate
|
||||
)
|
||||
internal
|
||||
{
|
||||
require(_node != RESERVED_NODE);
|
||||
NodeInfo storage nodeInfo = nodes[_node];
|
||||
require(nodeInfo.previousFeePeriod != 0 &&
|
||||
nodeInfo.previousFeePeriod < _currentPeriod &&
|
||||
_feeRate >= getMinFeeRate(nodeInfo));
|
||||
// Check default value for feeDelta
|
||||
if (nodeInfo.feeDelta[_currentPeriod] == DEFAULT_FEE_DELTA) {
|
||||
nodeInfo.feeDelta[_currentPeriod] = _overallFeeRate;
|
||||
} else {
|
||||
// Overflow protection removed, because ETH total supply less than uint255/int256
|
||||
nodeInfo.feeDelta[_currentPeriod] += _overallFeeRate;
|
||||
}
|
||||
if (nodeInfo.feeDelta[_endPeriod] == DEFAULT_FEE_DELTA) {
|
||||
nodeInfo.feeDelta[_endPeriod] = -_overallFeeRate;
|
||||
} else {
|
||||
nodeInfo.feeDelta[_endPeriod] -= _overallFeeRate;
|
||||
}
|
||||
// Reset to default value if needed
|
||||
if (nodeInfo.feeDelta[_currentPeriod] == 0) {
|
||||
nodeInfo.feeDelta[_currentPeriod] = DEFAULT_FEE_DELTA;
|
||||
}
|
||||
if (nodeInfo.feeDelta[_endPeriod] == 0) {
|
||||
nodeInfo.feeDelta[_endPeriod] = DEFAULT_FEE_DELTA;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get policy owner
|
||||
*/
|
||||
|
|
|
@ -104,7 +104,7 @@ def test_create_revoke(testerchain, escrow, policy_manager):
|
|||
# Can't create policy using timestamp from the past
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = policy_manager.functions.createPolicy(policy_id, policy_sponsor, current_timestamp -1, [node1])\
|
||||
.transact({'from': policy_sponsor})
|
||||
.transact({'from': policy_sponsor, 'value': value})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Create policy
|
||||
|
@ -517,6 +517,240 @@ def test_create_revoke(testerchain, escrow, policy_manager):
|
|||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
|
||||
def test_create_multiple_policies(testerchain, escrow, policy_manager):
|
||||
creator, policy_sponsor, bad_node, node1, node2, node3, policy_owner, *everyone_else = testerchain.client.accounts
|
||||
|
||||
rate = 20
|
||||
one_period = 60 * 60
|
||||
number_of_periods = 10
|
||||
value = rate * number_of_periods
|
||||
default_fee_delta = policy_manager.functions.DEFAULT_FEE_DELTA().call()
|
||||
|
||||
policy_sponsor_balance = testerchain.client.get_balance(policy_sponsor)
|
||||
policy_created_log = policy_manager.events.PolicyCreated.createFilter(fromBlock='latest')
|
||||
|
||||
# Check registered nodes
|
||||
assert 0 < policy_manager.functions.nodes(node1).call()[PREVIOUS_FEE_PERIOD_FIELD]
|
||||
assert 0 < policy_manager.functions.nodes(node2).call()[PREVIOUS_FEE_PERIOD_FIELD]
|
||||
assert 0 < policy_manager.functions.nodes(node3).call()[PREVIOUS_FEE_PERIOD_FIELD]
|
||||
assert 0 == policy_manager.functions.nodes(bad_node).call()[PREVIOUS_FEE_PERIOD_FIELD]
|
||||
current_timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
end_timestamp = current_timestamp + (number_of_periods - 1) * one_period
|
||||
|
||||
policy_id_1 = os.urandom(POLICY_ID_LENGTH)
|
||||
policy_id_2 = os.urandom(POLICY_ID_LENGTH)
|
||||
policies = [policy_id_1, policy_id_2]
|
||||
|
||||
# Try to create policy for bad (unregistered) node
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = policy_manager.functions.createPolicies(policies, policy_sponsor, end_timestamp, [bad_node])\
|
||||
.transact({'from': policy_sponsor, 'value': 2 * value})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = policy_manager.functions.createPolicies(policies, policy_sponsor, end_timestamp, [node1, bad_node])\
|
||||
.transact({'from': policy_sponsor, 'value': 2 * value})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Try to create policy with no ETH
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = policy_manager.functions.createPolicies(policies, policy_sponsor, end_timestamp, [node1])\
|
||||
.transact({'from': policy_sponsor})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Can't create policy using timestamp from the past
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = policy_manager.functions.createPolicies(policies, policy_sponsor, current_timestamp - 1, [node1])\
|
||||
.transact({'from': policy_sponsor, 'value': 2 * value})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Can't create two policies with the same id
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = policy_manager.functions.createPolicies([policy_id_1, policy_id_1], policy_sponsor, end_timestamp, [node1]) \
|
||||
.transact({'from': policy_sponsor, 'value': 2 * value, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Can't use createPolicies() method for only one policy
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = policy_manager.functions.createPolicies([policy_id_1], policy_sponsor, end_timestamp, [node1]) \
|
||||
.transact({'from': policy_sponsor, 'value': value, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Create policy
|
||||
current_period = escrow.functions.getCurrentPeriod().call()
|
||||
tx = policy_manager.functions.createPolicies(policies, policy_sponsor, end_timestamp, [node1])\
|
||||
.transact({'from': policy_sponsor, 'value': 2 * value, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
current_timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
# Check balances and policy info
|
||||
assert 2 * value == testerchain.client.get_balance(policy_manager.address)
|
||||
assert policy_sponsor_balance - 2 * value == testerchain.client.get_balance(policy_sponsor)
|
||||
|
||||
events = policy_created_log.get_all_entries()
|
||||
assert len(events) == 2
|
||||
|
||||
for i, policy_id in enumerate(policies):
|
||||
policy = policy_manager.functions.policies(policy_id).call()
|
||||
assert policy_sponsor == policy[SPONSOR_FIELD]
|
||||
assert NULL_ADDRESS == policy[OWNER_FIELD]
|
||||
assert rate == policy[RATE_FIELD]
|
||||
assert current_timestamp == policy[START_TIMESTAMP_FIELD]
|
||||
assert end_timestamp == policy[END_TIMESTAMP_FIELD]
|
||||
assert not policy[DISABLED_FIELD]
|
||||
assert 1 == policy_manager.functions.getArrangementsLength(policy_id).call()
|
||||
assert node1 == policy_manager.functions.getArrangementInfo(policy_id, 0).call()[0]
|
||||
assert policy_sponsor == policy_manager.functions.getPolicyOwner(policy_id).call()
|
||||
assert policy_manager.functions.getNodeFeeDelta(node1, current_period).call() == 2 * rate
|
||||
assert policy_manager.functions.getNodeFeeDelta(node1, current_period + number_of_periods).call() == -2 * rate
|
||||
|
||||
event_args = events[i]['args']
|
||||
assert policy_id == event_args['policyId']
|
||||
assert policy_sponsor == event_args['sponsor']
|
||||
assert policy_sponsor == event_args['owner']
|
||||
assert rate == event_args['feeRate']
|
||||
assert current_timestamp == event_args['startTimestamp']
|
||||
assert end_timestamp == event_args['endTimestamp']
|
||||
assert 1 == event_args['numberOfNodes']
|
||||
|
||||
# Can't create policy with the same id
|
||||
policy_id_3 = os.urandom(POLICY_ID_LENGTH)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = policy_manager.functions.createPolicies([policy_id_3, policy_id_1], policy_sponsor, end_timestamp, [node1])\
|
||||
.transact({'from': policy_sponsor, 'value': 2 * value})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Revoke policies
|
||||
tx = policy_manager.functions.revokePolicy(policy_id_1).transact({'from': policy_sponsor, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = policy_manager.functions.revokePolicy(policy_id_2).transact({'from': policy_sponsor, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert policy_manager.functions.policies(policy_id_1).call()[DISABLED_FIELD]
|
||||
assert policy_manager.functions.policies(policy_id_2).call()[DISABLED_FIELD]
|
||||
|
||||
# Create new policy
|
||||
testerchain.time_travel(hours=1)
|
||||
current_period = escrow.functions.getCurrentPeriod().call()
|
||||
for period_to_set_default in range(current_period, current_period + number_of_periods + 1):
|
||||
tx = escrow.functions.ping(node1, 0, 0, period_to_set_default).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = escrow.functions.ping(node2, 0, 0, period_to_set_default).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
current_timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
end_timestamp = current_timestamp + (number_of_periods - 1) * one_period
|
||||
policy_id_1 = os.urandom(POLICY_ID_LENGTH)
|
||||
policy_id_2 = os.urandom(POLICY_ID_LENGTH)
|
||||
policies = [policy_id_1, policy_id_2]
|
||||
tx = policy_manager.functions.createPolicies(policies, policy_owner, end_timestamp, [node1, node2, node3])\
|
||||
.transact({'from': policy_sponsor, 'value': 6 * value, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
current_timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert 6 * value == testerchain.client.get_balance(policy_manager.address)
|
||||
assert policy_sponsor_balance - 6 * value == testerchain.client.get_balance(policy_sponsor)
|
||||
events = policy_created_log.get_all_entries()
|
||||
assert len(events) == 4
|
||||
|
||||
for i, policy_id in enumerate(policies):
|
||||
policy = policy_manager.functions.policies(policy_id).call()
|
||||
assert policy_sponsor == policy[SPONSOR_FIELD]
|
||||
assert policy_owner == policy[OWNER_FIELD]
|
||||
assert rate == policy[RATE_FIELD]
|
||||
assert current_timestamp == policy[START_TIMESTAMP_FIELD]
|
||||
assert end_timestamp == policy[END_TIMESTAMP_FIELD]
|
||||
assert not policy[DISABLED_FIELD]
|
||||
assert policy_owner == policy_manager.functions.getPolicyOwner(policy_id).call()
|
||||
assert policy_manager.functions.getNodeFeeDelta(node1, current_period).call() == default_fee_delta
|
||||
assert policy_manager.functions.getNodeFeeDelta(node1, current_period + number_of_periods).call() == -2 * rate
|
||||
assert policy_manager.functions.getNodeFeeDelta(node2, current_period).call() == 2 * rate
|
||||
assert policy_manager.functions.getNodeFeeDelta(node2, current_period + number_of_periods).call() == -2 * rate
|
||||
assert policy_manager.functions.getNodeFeeDelta(node3, current_period).call() == 2 * rate
|
||||
assert policy_manager.functions.getNodeFeeDelta(node3, current_period + number_of_periods).call() == -2 * rate
|
||||
|
||||
event_args = events[i + 2]['args']
|
||||
assert policy_id == event_args['policyId']
|
||||
assert policy_sponsor == event_args['sponsor']
|
||||
assert policy_owner == event_args['owner']
|
||||
assert rate == event_args['feeRate']
|
||||
assert current_timestamp == event_args['startTimestamp']
|
||||
assert end_timestamp == event_args['endTimestamp']
|
||||
assert 3 == event_args['numberOfNodes']
|
||||
|
||||
# Revoke policies
|
||||
tx = policy_manager.functions.revokePolicy(policy_id_1).transact({'from': policy_owner, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = policy_manager.functions.revokePolicy(policy_id_2).transact({'from': policy_owner, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert policy_manager.functions.policies(policy_id_1).call()[DISABLED_FIELD]
|
||||
assert policy_manager.functions.policies(policy_id_2).call()[DISABLED_FIELD]
|
||||
|
||||
# Can't create policy with wrong ETH value - when fee is not calculated by formula:
|
||||
# numberOfNodes * feeRate * numberOfPeriods * numberOfPolicies
|
||||
policy_id_1 = os.urandom(POLICY_ID_LENGTH)
|
||||
policy_id_2 = os.urandom(POLICY_ID_LENGTH)
|
||||
policies = [policy_id_1, policy_id_2]
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = policy_manager.functions.createPolicies(policies, policy_sponsor, end_timestamp, [node1])\
|
||||
.transact({'from': policy_sponsor, 'value': value - 1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
min_rate, default_rate, max_rate = 10, 20, 30
|
||||
tx = policy_manager.functions.setFeeRateRange(min_rate, default_rate, max_rate).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Set minimum fee rate for nodes
|
||||
tx = policy_manager.functions.setMinFeeRate(10).transact({'from': node1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = policy_manager.functions.setMinFeeRate(20).transact({'from': node2})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert policy_manager.functions.nodes(node1).call()[MIN_FEE_RATE_FIELD] == 10
|
||||
assert policy_manager.functions.nodes(node2).call()[MIN_FEE_RATE_FIELD] == 20
|
||||
assert policy_manager.functions.getMinFeeRate(node1).call() == 10
|
||||
assert policy_manager.functions.getMinFeeRate(node2).call() == 20
|
||||
|
||||
# Try to create policy with low rate
|
||||
current_timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
end_timestamp = current_timestamp + 10
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = policy_manager.functions.createPolicies(policies, policy_sponsor, end_timestamp, [node1])\
|
||||
.transact({'from': policy_sponsor, 'value': 2 * (min_rate - 1)})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = policy_manager.functions.createPolicies(policies, policy_sponsor, end_timestamp, [node1, node2])\
|
||||
.transact({'from': policy_sponsor, 'value': 2 * 2 * (min_rate + 1)})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Create new policy
|
||||
value = 2 * default_rate * number_of_periods
|
||||
end_timestamp = current_timestamp + (number_of_periods - 1) * one_period
|
||||
tx = policy_manager.functions.createPolicies(
|
||||
policies, NULL_ADDRESS, end_timestamp, [node1, node2]) \
|
||||
.transact({'from': policy_sponsor, 'value': 2 * value, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
current_timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert 2 * value == testerchain.client.get_balance(policy_manager.address)
|
||||
assert policy_sponsor_balance - 2 * value == testerchain.client.get_balance(policy_sponsor)
|
||||
events = policy_created_log.get_all_entries()
|
||||
assert len(events) == 6
|
||||
|
||||
for i, policy_id in enumerate(policies):
|
||||
policy = policy_manager.functions.policies(policy_id).call()
|
||||
assert policy_sponsor == policy[SPONSOR_FIELD]
|
||||
assert NULL_ADDRESS == policy[OWNER_FIELD]
|
||||
assert default_rate == policy[RATE_FIELD]
|
||||
assert current_timestamp == policy[START_TIMESTAMP_FIELD]
|
||||
assert end_timestamp == policy[END_TIMESTAMP_FIELD]
|
||||
assert not policy[DISABLED_FIELD]
|
||||
assert policy_sponsor == policy_manager.functions.getPolicyOwner(policy_id).call()
|
||||
|
||||
event_args = events[i + 4]['args']
|
||||
assert policy_id == event_args['policyId']
|
||||
assert policy_sponsor == event_args['sponsor']
|
||||
assert policy_sponsor == event_args['owner']
|
||||
assert rate == event_args['feeRate']
|
||||
assert current_timestamp == event_args['startTimestamp']
|
||||
assert end_timestamp == event_args['endTimestamp']
|
||||
assert 2 == event_args['numberOfNodes']
|
||||
|
||||
|
||||
def test_upgrading(testerchain, deploy_contract):
|
||||
creator = testerchain.client.accounts[0]
|
||||
|
||||
|
|
|
@ -448,7 +448,26 @@ def estimate_gas(analyzer: AnalyzeGas = None) -> None:
|
|||
policy_functions.revokePolicy(policy_id_3),
|
||||
{'from': alice2})
|
||||
|
||||
for index in range(5):
|
||||
transact(staker_functions.commitToNextPeriod(), {'from': staker1})
|
||||
transact(staker_functions.commitToNextPeriod(), {'from': staker2})
|
||||
transact(staker_functions.commitToNextPeriod(), {'from': staker3})
|
||||
testerchain.time_travel(periods=1)
|
||||
#
|
||||
# Batch granting
|
||||
#
|
||||
policy_id_1 = os.urandom(int(Policy.POLICY_ID_LENGTH))
|
||||
policy_id_2 = os.urandom(int(Policy.POLICY_ID_LENGTH))
|
||||
current_timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
end_timestamp = current_timestamp + (number_of_periods - 1) * one_period
|
||||
value = 3 * number_of_periods * rate
|
||||
transact_and_log("Creating 2 policies (3 nodes, 100 periods, pre-committed)",
|
||||
policy_functions.createPolicies([policy_id_1, policy_id_2],
|
||||
alice1,
|
||||
end_timestamp,
|
||||
[staker1, staker2, staker3]),
|
||||
{'from': alice1, 'value': 2 * value})
|
||||
|
||||
for index in range(4):
|
||||
transact(staker_functions.commitToNextPeriod(), {'from': staker1})
|
||||
testerchain.time_travel(periods=1)
|
||||
transact(staker_functions.mint(), {'from': staker1})
|
||||
|
|
Loading…
Reference in New Issue