Extracted getLockedTokensInPast method, some optimization

pull/507/head
szotov 2018-12-19 15:49:09 +03:00
parent f4cd8245de
commit 9b4d77c035
4 changed files with 72 additions and 40 deletions

View File

@ -210,29 +210,56 @@ contract MinersEscrow is Issuer {
return getLastPeriodOfSubStake(subStake, startPeriod);
}
/**
* @notice Get the value of locked tokens for a miner in a specified period
* @dev Information may be incorrect for mined or unconfirmed surpassed period
* @param _miner Miner
* @param _periods Amount of periods that will be added to the current period
* @param _info Miner structure
* @param _currentPeriod Current period
* @param _period Next period
**/
function getLockedTokens(address _miner, int16 _periods)
public view returns (uint256 lockedValue)
function getLockedTokens(MinerInfo storage _info, uint16 _currentPeriod, uint16 _period)
internal view returns (uint256 lockedValue)
{
uint16 startPeriod = getCurrentPeriod();
uint16 nextPeriod = startPeriod.addSigned16(_periods);
MinerInfo storage info = minerInfo[_miner];
startPeriod = getStartPeriod(info, startPeriod);
for (uint256 i = 0; i < info.subStakes.length; i++) {
SubStakeInfo storage subStake = info.subStakes[i];
if (subStake.firstPeriod <= nextPeriod &&
getLastPeriodOfSubStake(subStake, startPeriod) >= nextPeriod) {
uint16 startPeriod = getStartPeriod(_info, _currentPeriod);
for (uint256 i = 0; i < _info.subStakes.length; i++) {
SubStakeInfo storage subStake = _info.subStakes[i];
if (subStake.firstPeriod <= _period &&
getLastPeriodOfSubStake(subStake, startPeriod) >= _period) {
lockedValue = lockedValue.add(subStake.lockedValue);
}
}
}
/**
* @notice Get the value of locked tokens for a miner in a future period
* @param _miner Miner
* @param _periods Amount of periods that will be added to the current period
**/
function getLockedTokens(address _miner, uint16 _periods)
public view returns (uint256 lockedValue)
{
MinerInfo storage info = minerInfo[_miner];
uint16 currentPeriod = getCurrentPeriod();
uint16 nextPeriod = currentPeriod.add16(_periods);
return getLockedTokens(info, currentPeriod, nextPeriod);
}
/**
* @notice Get the value of locked tokens for a miner in a previous period
* @dev Information may be incorrect for mined or unconfirmed surpassed period
* @param _miner Miner
* @param _periods Amount of periods that will be subtracted from the current period
**/
function getLockedTokensInPast(address _miner, uint16 _periods)
public view returns (uint256 lockedValue)
{
MinerInfo storage info = minerInfo[_miner];
uint16 currentPeriod = getCurrentPeriod();
uint16 previousPeriod = currentPeriod.sub16(_periods);
return getLockedTokens(info, currentPeriod, previousPeriod);
}
/**
* @notice Get the value of locked tokens for a miner in the current period
* @param _miner Miner
@ -265,6 +292,7 @@ contract MinersEscrow is Issuer {
{
require(_periods > 0);
uint16 currentPeriod = getCurrentPeriod();
uint16 nextPeriod = currentPeriod.add16(_periods);
for (uint256 i = 0; i < miners.length; i++) {
address miner = miners[i];
MinerInfo storage info = minerInfo[miner];
@ -272,7 +300,7 @@ contract MinersEscrow is Issuer {
info.confirmedPeriod2 != currentPeriod) {
continue;
}
lockedTokens = lockedTokens.add(getLockedTokens(miner, int16(_periods)));
lockedTokens = lockedTokens.add(getLockedTokens(info, currentPeriod, nextPeriod));
}
}
@ -393,12 +421,13 @@ contract MinersEscrow is Issuer {
uint16 lastActivePeriod = getLastActivePeriod(_miner);
mint(_miner);
uint256 lockedTokens = getLockedTokens(_miner, 1);
uint16 currentPeriod = getCurrentPeriod();
uint16 nextPeriod = currentPeriod.add16(1);
MinerInfo storage info = minerInfo[_miner];
uint256 lockedTokens = getLockedTokens(info, currentPeriod, nextPeriod);
require(_value.add(lockedTokens) <= info.value &&
_value.add(lockedTokens) <= maxAllowableLockedTokens);
uint16 nextPeriod = getCurrentPeriod().add16(1);
if (info.confirmedPeriod1 != nextPeriod && info.confirmedPeriod2 != nextPeriod) {
saveSubStake(info, nextPeriod, 0, _periods, _value);
} else {
@ -487,11 +516,13 @@ contract MinersEscrow is Issuer {
* @param _value Amount of tokens to withdraw
**/
function withdraw(uint256 _value) public onlyMiner {
uint16 currentPeriod = getCurrentPeriod();
uint16 nextPeriod = currentPeriod.add16(1);
MinerInfo storage info = minerInfo[msg.sender];
// the max locked tokens in most cases will be in the current period
// but when the miner stakes more then we should use the next period
uint256 lockedTokens = Math.max(getLockedTokens(msg.sender, 1),
getLockedTokens(msg.sender, 0));
uint256 lockedTokens = Math.max(getLockedTokens(info, currentPeriod, nextPeriod),
getLockedTokens(info, currentPeriod, currentPeriod));
require(_value <= token.balanceOf(address(this)) &&
_value <= info.value.sub(lockedTokens));
info.value -= _value;
@ -561,7 +592,7 @@ contract MinersEscrow is Issuer {
mint(msg.sender);
MinerInfo storage info = minerInfo[msg.sender];
uint16 currentPeriod = getCurrentPeriod();
uint16 nextPeriod = currentPeriod + 1;
uint16 nextPeriod = currentPeriod.add16(1);
// the period has already been confirmed
if (info.confirmedPeriod1 == nextPeriod ||
@ -569,7 +600,7 @@ contract MinersEscrow is Issuer {
return;
}
uint256 lockedTokens = getLockedTokens(msg.sender, 1);
uint256 lockedTokens = getLockedTokens(info, currentPeriod, nextPeriod);
confirmActivity(msg.sender, lockedTokens, 0, lastActivePeriod);
}
@ -696,6 +727,7 @@ contract MinersEscrow is Issuer {
{
require(_periods > 0 && _points.length > 0);
uint16 currentPeriod = getCurrentPeriod();
uint16 nextPeriod = currentPeriod.add16(_periods);
result = new address[](_points.length);
uint256 pointIndex = 0;
@ -713,7 +745,7 @@ contract MinersEscrow is Issuer {
continue;
}
if (addMoreTokens) {
sumOfLockedTokens = sumOfLockedTokens.add(getLockedTokens(currentMiner, int16(_periods)));
sumOfLockedTokens = sumOfLockedTokens.add(getLockedTokens(info, currentPeriod, nextPeriod));
}
if (sumOfLockedTokens > point) {
result[pointIndex] = currentMiner;

View File

@ -151,4 +151,4 @@ contract ChallengeOverseerForMinersEscrowMock {
{
escrow.slashMiner(_miner, _penalty, _investigator, _reward);
}
}
}

View File

@ -589,7 +589,7 @@ def test_all(testerchain, token, escrow, policy_manager, overseer, user_escrow_p
# Slash part of the free amount of tokens
period = escrow.functions.getCurrentPeriod().call()
tokens_amount = escrow.functions.minerInfo(ursula1).call()[VALUE_FIELD]
previous_lock = escrow.functions.getLockedTokens(ursula1, -1).call()
previous_lock = escrow.functions.getLockedTokensInPast(ursula1, 1).call()
lock = escrow.functions.getLockedTokens(ursula1).call()
next_lock = escrow.functions.getLockedTokens(ursula1, 1).call()
total_previous_lock = escrow.functions.lockedPerPeriod(period - 1).call()
@ -598,7 +598,7 @@ def test_all(testerchain, token, escrow, policy_manager, overseer, user_escrow_p
tx = overseer.functions.slashMiner(ursula1, 100, alice1, 10).transact()
testerchain.wait_for_receipt(tx)
assert tokens_amount - 100 == escrow.functions.minerInfo(ursula1).call()[VALUE_FIELD]
assert previous_lock == escrow.functions.getLockedTokens(ursula1, -1).call()
assert previous_lock == escrow.functions.getLockedTokensInPast(ursula1, 1).call()
assert lock == escrow.functions.getLockedTokens(ursula1).call()
assert next_lock == escrow.functions.getLockedTokens(ursula1, 1).call()
assert total_previous_lock == escrow.functions.lockedPerPeriod(period - 1).call()
@ -609,13 +609,13 @@ def test_all(testerchain, token, escrow, policy_manager, overseer, user_escrow_p
# Slash part of the one sub stake
tokens_amount = escrow.functions.minerInfo(ursula2).call()[VALUE_FIELD]
unlocked_amount = tokens_amount - escrow.functions.getLockedTokens(ursula2).call()
previous_lock = escrow.functions.getLockedTokens(ursula2, -1).call()
previous_lock = escrow.functions.getLockedTokensInPast(ursula2, 1).call()
lock = escrow.functions.getLockedTokens(ursula2).call()
next_lock = escrow.functions.getLockedTokens(ursula2, 1).call()
tx = overseer.functions.slashMiner(ursula2, unlocked_amount + 100, alice1, 20).transact()
testerchain.wait_for_receipt(tx)
assert lock - 100 == escrow.functions.minerInfo(ursula2).call()[VALUE_FIELD]
assert previous_lock == escrow.functions.getLockedTokens(ursula2, -1).call()
assert previous_lock == escrow.functions.getLockedTokensInPast(ursula2, 1).call()
assert lock - 100 == escrow.functions.getLockedTokens(ursula2).call()
assert next_lock - 100 == escrow.functions.getLockedTokens(ursula2, 1).call()
assert total_previous_lock == escrow.functions.lockedPerPeriod(period - 1).call()
@ -626,14 +626,14 @@ def test_all(testerchain, token, escrow, policy_manager, overseer, user_escrow_p
# Slash two sub stakes
tokens_amount = escrow.functions.minerInfo(user_escrow_1.address).call()[VALUE_FIELD]
unlocked_amount = tokens_amount - escrow.functions.getLockedTokens(user_escrow_1.address).call()
previous_lock = escrow.functions.getLockedTokens(user_escrow_1.address, -1).call()
previous_lock = escrow.functions.getLockedTokensInPast(user_escrow_1.address, 1).call()
lock = escrow.functions.getLockedTokens(user_escrow_1.address).call()
next_lock = escrow.functions.getLockedTokens(user_escrow_1.address, 1).call()
alice2_balance = token.functions.balanceOf(alice2).call()
tx = overseer.functions.slashMiner(user_escrow_1.address, unlocked_amount + 600, alice2, 60).transact()
testerchain.wait_for_receipt(tx)
assert lock - 600 == escrow.functions.minerInfo(user_escrow_1.address).call()[VALUE_FIELD]
assert previous_lock == escrow.functions.getLockedTokens(user_escrow_1.address, -1).call()
assert previous_lock == escrow.functions.getLockedTokensInPast(user_escrow_1.address, 1).call()
assert lock - 600 == escrow.functions.getLockedTokens(user_escrow_1.address).call()
assert next_lock - 600 == escrow.functions.getLockedTokens(user_escrow_1.address, 1).call()
assert total_previous_lock == escrow.functions.lockedPerPeriod(period - 1).call()

View File

@ -402,7 +402,7 @@ def test_slashing(testerchain, token, escrow_contract):
testerchain.wait_for_receipt(tx)
testerchain.time_travel(hours=1)
period += 1
assert 90 == escrow.functions.getLockedTokens(ursula, -1).call()
assert 90 == escrow.functions.getLockedTokensInPast(ursula, 1).call()
assert 190 == escrow.functions.getLockedTokens(ursula).call()
assert 100 == escrow.functions.getLockedTokens(ursula, 4).call()
assert 190 == escrow.functions.minerInfo(ursula).call()[VALUE_FIELD]
@ -415,7 +415,7 @@ def test_slashing(testerchain, token, escrow_contract):
tx = overseer.functions.slashMiner(ursula, 10, investigator, 0).transact()
testerchain.wait_for_receipt(tx)
assert 180 == escrow.functions.minerInfo(ursula).call()[VALUE_FIELD]
assert 90 == escrow.functions.getLockedTokens(ursula, -1).call()
assert 90 == escrow.functions.getLockedTokensInPast(ursula, 1).call()
assert 180 == escrow.functions.getLockedTokens(ursula).call()
assert 100 == escrow.functions.getLockedTokens(ursula, 4).call()
assert 20 == token.functions.balanceOf(investigator).call()
@ -436,7 +436,7 @@ def test_slashing(testerchain, token, escrow_contract):
testerchain.wait_for_receipt(tx)
testerchain.time_travel(hours=2)
period += 2
assert 290 == escrow.functions.getLockedTokens(ursula, -1).call()
assert 290 == escrow.functions.getLockedTokensInPast(ursula, 1).call()
assert 290 == escrow.functions.getLockedTokens(ursula).call()
assert 180 == escrow.functions.getLockedTokens(ursula, 2).call()
deposit = escrow.functions.minerInfo(ursula).call()[VALUE_FIELD] # Some reward is already mined
@ -448,7 +448,7 @@ def test_slashing(testerchain, token, escrow_contract):
tx = overseer.functions.slashMiner(ursula, deposit - 290, investigator, 0).transact()
testerchain.wait_for_receipt(tx)
assert 290 == escrow.functions.minerInfo(ursula).call()[VALUE_FIELD]
assert 290 == escrow.functions.getLockedTokens(ursula, -1).call()
assert 290 == escrow.functions.getLockedTokensInPast(ursula, 1).call()
assert 290 == escrow.functions.getLockedTokens(ursula).call()
assert 180 == escrow.functions.getLockedTokens(ursula, 2).call()
assert 20 == token.functions.balanceOf(investigator).call()
@ -468,7 +468,7 @@ def test_slashing(testerchain, token, escrow_contract):
tx = overseer.functions.slashMiner(ursula, 20, investigator, 0).transact()
testerchain.wait_for_receipt(tx)
assert 270 == escrow.functions.minerInfo(ursula).call()[VALUE_FIELD]
assert 290 == escrow.functions.getLockedTokens(ursula, -1).call()
assert 290 == escrow.functions.getLockedTokensInPast(ursula, 1).call()
assert 270 == escrow.functions.getLockedTokens(ursula).call()
assert 180 == escrow.functions.getLockedTokens(ursula, 2).call()
assert 20 == token.functions.balanceOf(investigator).call()
@ -489,7 +489,7 @@ def test_slashing(testerchain, token, escrow_contract):
tx = overseer.functions.slashMiner(ursula, 100, investigator, 0).transact()
testerchain.wait_for_receipt(tx)
assert 170 == escrow.functions.minerInfo(ursula).call()[VALUE_FIELD]
assert 290 == escrow.functions.getLockedTokens(ursula, -1).call()
assert 290 == escrow.functions.getLockedTokensInPast(ursula, 1).call()
assert 170 == escrow.functions.getLockedTokens(ursula).call()
assert 170 == escrow.functions.getLockedTokens(ursula, 2).call()
assert 20 == token.functions.balanceOf(investigator).call()
@ -618,16 +618,16 @@ def test_slashing(testerchain, token, escrow_contract):
tx = escrow.functions.deposit(100, 2).transact({'from': ursula2})
testerchain.wait_for_receipt(tx)
testerchain.time_travel(hours=2)
assert 100 == escrow.functions.getLockedTokens(ursula2, -2).call()
assert 200 == escrow.functions.getLockedTokens(ursula2, -1).call()
assert 100 == escrow.functions.getLockedTokensInPast(ursula2, 2).call()
assert 200 == escrow.functions.getLockedTokensInPast(ursula2, 1).call()
assert 200 == escrow.functions.getLockedTokens(ursula2).call()
assert 200 == escrow.functions.getLockedTokens(ursula2, 1).call()
# Slash one sub stake to set the last period of this sub stake to the previous period
tx = overseer.functions.slashMiner(ursula2, 100, investigator, 0).transact()
testerchain.wait_for_receipt(tx)
assert 100 == escrow.functions.getLockedTokens(ursula2, -2).call()
assert 200 == escrow.functions.getLockedTokens(ursula2, -1).call()
assert 100 == escrow.functions.getLockedTokensInPast(ursula2, 2).call()
assert 200 == escrow.functions.getLockedTokensInPast(ursula2, 1).call()
assert 100 == escrow.functions.getLockedTokens(ursula2).call()
assert 100 == escrow.functions.getLockedTokens(ursula2, 1).call()
@ -643,8 +643,8 @@ def test_slashing(testerchain, token, escrow_contract):
# and check that the second sub stake will not combine with the slashed amount of the first one
tx = overseer.functions.slashMiner(ursula2, 50, investigator, 0).transact()
testerchain.wait_for_receipt(tx)
assert 100 == escrow.functions.getLockedTokens(ursula2, -2).call()
assert 200 == escrow.functions.getLockedTokens(ursula2, -1).call()
assert 100 == escrow.functions.getLockedTokensInPast(ursula2, 2).call()
assert 200 == escrow.functions.getLockedTokensInPast(ursula2, 1).call()
assert 50 == escrow.functions.getLockedTokens(ursula2).call()
assert 50 == escrow.functions.getLockedTokens(ursula2, 1).call()