Improved tests for slashing

pull/507/head
szotov 2018-11-20 15:13:11 +03:00
parent dbeb29fe83
commit df99cb650e
4 changed files with 52 additions and 10 deletions

View File

@ -166,6 +166,13 @@ contract Issuer is Upgradeable {
currentSupply2 = currentSupply2.sub(_amount);
}
/**
* @notice Returns the number of tokens that can be mined
**/
function getReservedReward() public view returns (uint256) {
return totalSupply - Math.max256(currentSupply1, currentSupply2);
}
function verifyState(address _testTarget) public onlyOwner {
require(address(uint160(delegateGet(_testTarget, "token()"))) == address(token));
require(delegateGet(_testTarget, "miningCoefficient()") == miningCoefficient);

View File

@ -748,7 +748,10 @@ contract MinersEscrow is Issuer {
}
}
unMint(_penalty - _reward);
_penalty = _penalty - _reward;
if (_penalty > 0) {
unMint(_penalty);
}
if (_reward > 0) {
token.safeTransfer(_investigator, _reward);
}
@ -784,9 +787,16 @@ contract MinersEscrow is Issuer {
uint256 appliedPenalty = _penalty;
if (_penalty < shortestSubStake.lockedValue) {
shortestSubStake.lockedValue -= _penalty;
if (_info.confirmedPeriod1 != EMPTY_CONFIRMED_PERIOD &&
_info.confirmedPeriod1 < _period ||
_info.confirmedPeriod2 != EMPTY_CONFIRMED_PERIOD &&
_info.confirmedPeriod2 < _period
) {
saveSubStake(_info, shortestSubStake.firstPeriod, _period.sub16(1), 0, _penalty);
}
_penalty = 0;
} else {
shortestSubStake.lastPeriod = 1;
shortestSubStake.lastPeriod = _period.sub16(1);
_penalty -= shortestSubStake.lockedValue;
appliedPenalty = shortestSubStake.lockedValue;
}

View File

@ -104,6 +104,7 @@ def test_inflation_rate(testerchain, token):
testerchain.wait_for_receipt(tx)
tx = issuer.functions.initialize().transact({'from': creator})
testerchain.wait_for_receipt(tx)
reward = issuer.functions.getReservedReward().call()
# Mint some tokens and save result of minting
period = issuer.functions.getCurrentPeriod().call()
@ -115,11 +116,13 @@ def test_inflation_rate(testerchain, token):
tx = issuer.functions.testMint(period + 1, 1, 1, 0).transact({'from': ursula})
testerchain.wait_for_receipt(tx)
assert 2 * one_period == token.functions.balanceOf(ursula).call()
assert reward - token.functions.balanceOf(ursula).call() == issuer.functions.getReservedReward().call()
# Mint tokens in the next period, inflation rate must be lower than in previous minting
tx = issuer.functions.testMint(period + 2, 1, 1, 0).transact({'from': ursula})
testerchain.wait_for_receipt(tx)
assert 3 * one_period > token.functions.balanceOf(ursula).call()
assert reward - token.functions.balanceOf(ursula).call() == issuer.functions.getReservedReward().call()
minted_amount = token.functions.balanceOf(ursula).call() - 2 * one_period
# Mint tokens in the first period again, inflation rate must be the same as in previous minting
@ -127,21 +130,26 @@ def test_inflation_rate(testerchain, token):
tx = issuer.functions.testMint(period + 1, 1, 1, 0).transact({'from': ursula})
testerchain.wait_for_receipt(tx)
assert 2 * one_period + 2 * minted_amount == token.functions.balanceOf(ursula).call()
assert reward - token.functions.balanceOf(ursula).call() == issuer.functions.getReservedReward().call()
# Mint tokens in the next period, inflation rate must be lower than in previous minting
tx = issuer.functions.testMint(period + 3, 1, 1, 0).transact({'from': ursula})
testerchain.wait_for_receipt(tx)
assert 2 * one_period + 3 * minted_amount > token.functions.balanceOf(ursula).call()
assert reward - token.functions.balanceOf(ursula).call() == issuer.functions.getReservedReward().call()
# Return some tokens as a reward
balance = token.functions.balanceOf(ursula).call()
reward = issuer.functions.getReservedReward().call()
tx = issuer.functions.testUnMint(2 * one_period + 2 * minted_amount).transact()
testerchain.wait_for_receipt(tx)
assert reward + 2 * one_period + 2 * minted_amount == issuer.functions.getReservedReward().call()
# Rate will be increased because some tokens were returned
tx = issuer.functions.testMint(period + 3, 1, 1, 0).transact({'from': ursula})
testerchain.wait_for_receipt(tx)
assert balance + one_period == token.functions.balanceOf(ursula).call()
assert reward + one_period + 2 * minted_amount == issuer.functions.getReservedReward().call()
@pytest.mark.slow

View File

@ -331,7 +331,17 @@ def test_slashing(testerchain, token, escrow_contract):
assert 100 == escrow.functions.lockedPerPeriod(period).call()
assert 0 == escrow.functions.lockedPerPeriod(period + 1).call()
# Can't slash directly using the escrow contract
with pytest.raises((TransactionFailed, ValueError)):
tx = escrow.functions.slashMiner(ursula, 100, investigator, 10).transact()
testerchain.wait_for_receipt(tx)
# Penalty must be greater than zero
with pytest.raises((TransactionFailed, ValueError)):
tx = escrow.functions.slashMiner(ursula, 0, investigator, 0).transact()
testerchain.wait_for_receipt(tx)
# Slash the whole stake
reward = escrow.functions.getReservedReward().call()
tx = overseer.functions.slashMiner(ursula, 100, investigator, 10).transact()
testerchain.wait_for_receipt(tx)
# Miner has no more sub stakes
@ -339,6 +349,7 @@ def test_slashing(testerchain, token, escrow_contract):
assert 0 == escrow.functions.getLockedTokens(ursula).call()
assert 10 == token.functions.balanceOf(investigator).call()
assert 0 == escrow.functions.lockedPerPeriod(period).call()
assert reward + 90 == escrow.functions.getReservedReward().call()
# New deposit and confirmation of activity
tx = escrow.functions.deposit(100, 5).transact({'from': ursula})
@ -353,6 +364,7 @@ def test_slashing(testerchain, token, escrow_contract):
assert 100 == escrow.functions.lockedPerPeriod(period + 1).call()
# Slash part of one sub stake (there is only one sub stake)
reward = escrow.functions.getReservedReward().call()
tx = overseer.functions.slashMiner(ursula, 10, investigator, 11).transact()
testerchain.wait_for_receipt(tx)
assert 90 == escrow.functions.minerInfo(ursula).call()[VALUE_FIELD]
@ -361,6 +373,7 @@ def test_slashing(testerchain, token, escrow_contract):
assert 20 == token.functions.balanceOf(investigator).call()
assert 90 == escrow.functions.lockedPerPeriod(period).call()
assert 90 == escrow.functions.lockedPerPeriod(period + 1).call()
assert reward == escrow.functions.getReservedReward().call()
# New deposit of a longer sub stake
tx = escrow.functions.deposit(100, 6).transact({'from': ursula})
@ -376,6 +389,7 @@ def test_slashing(testerchain, token, escrow_contract):
assert 0 == escrow.functions.lockedPerPeriod(period + 1).call()
# Slash again part of the first sub stake because new sub stake is longer (there are two sub stakes)
reward = escrow.functions.getReservedReward().call()
tx = overseer.functions.slashMiner(ursula, 10, investigator, 0).transact()
testerchain.wait_for_receipt(tx)
assert 180 == escrow.functions.minerInfo(ursula).call()[VALUE_FIELD]
@ -385,6 +399,7 @@ def test_slashing(testerchain, token, escrow_contract):
assert 20 == token.functions.balanceOf(investigator).call()
assert 90 == escrow.functions.lockedPerPeriod(period - 1).call()
assert 180 == escrow.functions.lockedPerPeriod(period).call()
assert reward + 10 == escrow.functions.getReservedReward().call()
# New deposit of a shorter sub stake
tx = escrow.functions.deposit(110, 2).transact({'from': ursula})
@ -399,6 +414,7 @@ def test_slashing(testerchain, token, escrow_contract):
assert 0 == escrow.functions.lockedPerPeriod(period).call()
# Slash only free amount of tokens
reward = escrow.functions.getReservedReward().call()
tx = overseer.functions.slashMiner(ursula, deposit - 290, investigator, 0).transact()
testerchain.wait_for_receipt(tx)
assert 290 == escrow.functions.minerInfo(ursula).call()[VALUE_FIELD]
@ -408,6 +424,7 @@ def test_slashing(testerchain, token, escrow_contract):
assert 20 == token.functions.balanceOf(investigator).call()
assert 290 == escrow.functions.lockedPerPeriod(period - 1).call()
assert 0 == escrow.functions.lockedPerPeriod(period).call()
assert reward + deposit - 290 == escrow.functions.getReservedReward().call()
# Slash only the new sub stake because it's the shortest one (there are three sub stakes)
tx = overseer.functions.slashMiner(ursula, 10, investigator, 0).transact()
@ -419,31 +436,31 @@ def test_slashing(testerchain, token, escrow_contract):
assert 20 == token.functions.balanceOf(investigator).call()
assert 290 == escrow.functions.lockedPerPeriod(period - 1).call()
assert 0 == escrow.functions.lockedPerPeriod(period).call()
assert reward + deposit - 280 == escrow.functions.getReservedReward().call()
# New deposit
tx = escrow.functions.deposit(100, 2).transact({'from': ursula})
testerchain.wait_for_receipt(tx)
assert 290 == escrow.functions.getLockedTokens(ursula, -1).call()
assert 280 == escrow.functions.getLockedTokens(ursula).call()
assert 380 == escrow.functions.getLockedTokens(ursula, 1).call()
assert 380 == escrow.functions.lockedPerPeriod(period + 1).call()
deposit = escrow.functions.minerInfo(ursula).call()[VALUE_FIELD] # Some reward is already mined
reward = deposit - 380
unlocked_deposit = deposit - 380
reward = escrow.functions.getReservedReward().call()
# Slash the new sub stake which starts in the next period
# Because locked value is more in the next period than in the current period
tx = overseer.functions.slashMiner(ursula, reward + 10, investigator, 0).transact()
tx = overseer.functions.slashMiner(ursula, unlocked_deposit + 10, investigator, 0).transact()
testerchain.wait_for_receipt(tx)
assert 290 == escrow.functions.getLockedTokens(ursula, -1).call()
assert 280 == escrow.functions.getLockedTokens(ursula).call()
assert 370 == escrow.functions.getLockedTokens(ursula, 1).call()
assert 370 == escrow.functions.minerInfo(ursula).call()[VALUE_FIELD]
assert 370 == escrow.functions.lockedPerPeriod(period + 1).call()
assert reward + unlocked_deposit + 10 == escrow.functions.getReservedReward().call()
# After two periods shortest sub stake will be unlocked, lock again and slash after this
testerchain.time_travel(hours=1)
period += 1
assert 280 == escrow.functions.getLockedTokens(ursula, -1).call()
assert 370 == escrow.functions.getLockedTokens(ursula).call()
assert 270 == escrow.functions.getLockedTokens(ursula, 1).call()
assert 100 == escrow.functions.getLockedTokens(ursula, 3).call()
@ -452,7 +469,6 @@ def test_slashing(testerchain, token, escrow_contract):
assert 0 == escrow.functions.lockedPerPeriod(period + 1).call()
tx = escrow.functions.lock(100, 2).transact({'from': ursula})
testerchain.wait_for_receipt(tx)
assert 280 == escrow.functions.getLockedTokens(ursula, -1).call()
assert 370 == escrow.functions.getLockedTokens(ursula).call()
assert 370 == escrow.functions.getLockedTokens(ursula, 1).call()
assert 100 == escrow.functions.getLockedTokens(ursula, 3).call()
@ -463,9 +479,9 @@ def test_slashing(testerchain, token, escrow_contract):
# Slash two sub stakes:
# one which will be unlocked after current period and new sub stake
reward = escrow.functions.getReservedReward().call()
tx = overseer.functions.slashMiner(ursula, 10, investigator, 0).transact()
testerchain.wait_for_receipt(tx)
assert 280 == escrow.functions.getLockedTokens(ursula, -1).call()
assert 360 == escrow.functions.getLockedTokens(ursula).call()
assert 360 == escrow.functions.getLockedTokens(ursula, 1).call()
assert 100 == escrow.functions.getLockedTokens(ursula, 3).call()
@ -473,12 +489,12 @@ def test_slashing(testerchain, token, escrow_contract):
assert 0 == escrow.functions.lockedPerPeriod(period - 1).call()
assert 360 == escrow.functions.lockedPerPeriod(period).call()
assert 360 == escrow.functions.lockedPerPeriod(period + 1).call()
assert reward + 10 == escrow.functions.getReservedReward().call()
# Slash three sub stakes:
# one which will be unlocked after current period, new sub stake and another short sub stake
tx = overseer.functions.slashMiner(ursula, 90, investigator, 0).transact()
testerchain.wait_for_receipt(tx)
assert 280 == escrow.functions.getLockedTokens(ursula, -1).call()
assert 270 == escrow.functions.getLockedTokens(ursula).call()
assert 270 == escrow.functions.getLockedTokens(ursula, 1).call()
assert 100 == escrow.functions.getLockedTokens(ursula, 3).call()
@ -486,3 +502,4 @@ def test_slashing(testerchain, token, escrow_contract):
assert 0 == escrow.functions.lockedPerPeriod(period - 1).call()
assert 270 == escrow.functions.lockedPerPeriod(period).call()
assert 270 == escrow.functions.lockedPerPeriod(period + 1).call()
assert reward + 100 == escrow.functions.getReservedReward().call()