Finished step-wise unlock and tests

pull/261/head
szotov 2018-04-26 17:14:07 +03:00
parent d81386175f
commit bce360b260
10 changed files with 382 additions and 304 deletions

View File

@ -96,19 +96,18 @@ class MinerAgent(EthereumContractAgent):
MINER = 1
VALUE = 2
DECIMALS = 3
LOCKED_VALUE = 4
RELEASE = 5
MAX_RELEASE_PERIODS = 6
RELEASE_RATE = 7
CONFIRMED_PERIODS_LENGTH = 8
CONFIRMED_PERIOD = 9
CONFIRMED_PERIOD_LOCKED_VALUE = 10
LAST_ACTIVE_PERIOD_F = 11
DOWNTIME_LENGTH = 12
DOWNTIME_START_PERIOD = 13
DOWNTIME_END_PERIOD = 14
MINER_IDS_LENGTH = 15
MINER_ID = 16
STAKES_LENGTH = 4
STAKE_FIRST_PERIOD = 5
STAKE_LAST_PERIOD_ = 6
STAKE_LOCKED_VALUE = 7
LAST_ACTIVE_PERIOD = 8
DOWNTIME_LENGTH = 9
DOWNTIME_START_PERIOD = 10
DOWNTIME_END_PERIOD = 11
MINER_IDS_LENGTH = 12
MINER_ID = 13
CONFIRMED_PERIOD_1 = 14
CONFIRMED_PERIOD_2 = 15
def __init__(self, token_agent: NuCypherKMSTokenAgent):
super().__init__(blockchain=token_agent.blockchain) # TODO: public

View File

@ -25,7 +25,13 @@ contract MinersEscrow is Issuer {
event Deposited(address indexed owner, uint256 value, uint256 periods);
event Locked(address indexed owner, uint256 value, uint256 firstPeriod, uint256 lastPeriod);
event Divided(address indexed owner, uint256 oldValue, uint256 newValue, uint256 periods);
event Divided(
address indexed owner,
uint256 oldValue,
uint256 lastPeriod,
uint256 newValue,
uint256 periods
);
event Withdrawn(address indexed owner, uint256 value);
event ActivityConfirmed(address indexed owner, uint256 indexed period, uint256 value);
event Mined(address indexed owner, uint256 indexed period, uint256 value);
@ -99,7 +105,7 @@ contract MinersEscrow is Issuer {
* @param _minAllowableLockedTokens Min amount of tokens that can be locked
* @param _maxAllowableLockedTokens Max amount of tokens that can be locked
**/
function MinersEscrow(
constructor(
NuCypherKMSToken _token,
uint256 _hoursPerPeriod,
uint256 _miningCoefficient,
@ -138,13 +144,12 @@ contract MinersEscrow is Issuer {
* @param _owner Tokens owner
**/
function getLockedTokens(address _owner, uint256 _periods)
public view returns (uint256)
public view returns (uint256 lockedValue)
{
uint256 currentPeriod = getCurrentPeriod();
uint256 nextPeriod = currentPeriod.add(_periods);
MinerInfo storage info = minerInfo[_owner];
uint256 lockedValue = 0;
for (uint256 i = 0; i < info.stakes.length; i++) {
StakeInfo storage stake = info.stakes[i];
if (stake.firstPeriod <= nextPeriod &&
@ -157,9 +162,8 @@ contract MinersEscrow is Issuer {
/**
* @notice Get locked tokens value for owner in future period
* @param _owner Tokens owner
* @param _periods Number of periods after current that need to calculate
**/
function getLockedTokens(address _owner, uint256 _periods)
function getLockedTokens(address _owner)
public view returns (uint256)
{
return getLockedTokens(_owner, 0);
@ -200,9 +204,9 @@ contract MinersEscrow is Issuer {
miners.push(owner);
info.lastActivePeriod = currentPeriod;
info.value = value;
info.stakes.push(StakeInfo(currentPeriod.add(1), currentPeriod.add(periods)), value);
info.stakes.push(StakeInfo(currentPeriod.add(uint256(1)), currentPeriod.add(periods), value));
allValue = allValue.add(value);
Deposited(owner, value, periods);
emit Deposited(owner, value, periods);
}
token.safeTransferFrom(msg.sender, address(this), allValue);
@ -211,7 +215,7 @@ contract MinersEscrow is Issuer {
/**
* @notice Deposit tokens
* @param _value Amount of token to deposit
* @param _periods Amount of periods during which tokens will be unlocked
* @param _periods Amount of periods during which tokens will be locked
**/
function deposit(uint256 _value, uint256 _periods) public isInitialized {
require(_value != 0);
@ -224,13 +228,13 @@ contract MinersEscrow is Issuer {
info.value = info.value.add(_value);
token.safeTransferFrom(msg.sender, address(this), _value);
lock(_value, _periods);
Deposited(msg.sender, _value, _periods);
emit Deposited(msg.sender, _value, _periods);
}
/**
* @notice Lock some tokens or increase lock
* @param _value Amount of tokens which should lock
* @param _periods Amount of periods during which tokens will be unlocked
* @param _periods Amount of periods during which tokens will be locked
**/
function lock(uint256 _value, uint256 _periods) public onlyTokenOwner {
require(_value != 0 || _periods != 0);
@ -245,30 +249,43 @@ contract MinersEscrow is Issuer {
_periods >= minLockedPeriods);
uint256 currentPeriod = getCurrentPeriod();
info.stakes.push(StakeInfo(currentPeriod.add(1), currentPeriod.add(_periods)), _value);
info.stakes.push(StakeInfo(currentPeriod.add(uint256(1)), currentPeriod.add(_periods), _value));
confirmActivity(_value + lockedTokens, _value);
Locked(msg.sender, _value, currentPeriod + 1, currentPeriod + _periods);
emit Locked(msg.sender, _value, currentPeriod + 1, currentPeriod + _periods);
}
/**
* @notice Divide stake into two parts
* @param _index Index of stake
* @param _value New stake value
* @param _oldValue Old stake value
* @param _lastPeriod Last period of stake
* @param _newValue New stake value
* @param _periods Amount of periods for extending stake
**/
function divideStake(uint256 _index, uint256 _value, uint256 _periods)
function divideStake(
uint256 _oldValue,
uint256 _lastPeriod,
uint256 _newValue,
uint256 _periods
)
public onlyTokenOwner
{
require(_value >= minAllowableLockedTokens);
require(_newValue >= minAllowableLockedTokens && _periods > 0);
MinerInfo storage info = minerInfo[msg.sender];
require(_index < info.stakes.length);
StakeInfo storage stake = info.stakes[_index];
require(stake.lockedValue.sub(_value) >= minAllowableLockedTokens);
Divided(msg.sender, stake.lockedValue, _value, _periods);
stake.lockedValue -= _value;
info.stakes.push(StakeInfo(stake.firstPeriod, stake.lastPeriod.add(_periods)), _value);
Locked(msg.sender, _value, stake.firstPeriod, stake.lastPeriod + _periods);
for (uint256 index = 0; index < info.stakes.length; index++) {
StakeInfo storage stake = info.stakes[index];
if (stake.lockedValue == _oldValue &&
stake.lastPeriod == _lastPeriod) {
break;
}
}
// TODO lastPeriod can be equal current period but need to call confirmActivity
require(index < info.stakes.length && stake.lastPeriod >= getCurrentPeriod().add(uint256(1)));
stake.lockedValue = stake.lockedValue.sub(_newValue);
require(stake.lockedValue >= minAllowableLockedTokens);
info.stakes.push(StakeInfo(stake.firstPeriod, stake.lastPeriod.add(_periods), _newValue));
emit Divided(msg.sender, _oldValue, _lastPeriod, _newValue, _periods);
emit Locked(msg.sender, _newValue, stake.firstPeriod, stake.lastPeriod + _periods);
}
/**
@ -284,7 +301,7 @@ contract MinersEscrow is Issuer {
_value <= info.value.sub(lockedTokens));
info.value -= _value;
token.safeTransfer(msg.sender, _value);
Withdrawn(msg.sender, _value);
emit Withdrawn(msg.sender, _value);
}
/**
@ -301,11 +318,11 @@ contract MinersEscrow is Issuer {
// update lockedValue if the period has already been confirmed
if (info.confirmedPeriod1 == nextPeriod) {
lockedPerPeriod[nextPeriod] = lockedPerPeriod[nextPeriod].add(_additional);
ActivityConfirmed(msg.sender, nextPeriod, _additional);
emit ActivityConfirmed(msg.sender, nextPeriod, _additional);
return;
} else if (info.confirmedPeriod2 == nextPeriod) {
lockedPerPeriod[nextPeriod] = lockedPerPeriod[nextPeriod].add(_additional);
ActivityConfirmed(msg.sender, nextPeriod, _additional);
emit ActivityConfirmed(msg.sender, nextPeriod, _additional);
return;
}
@ -321,7 +338,7 @@ contract MinersEscrow is Issuer {
info.downtime.push(Downtime(info.lastActivePeriod + 1, currentPeriod));
}
info.lastActivePeriod = nextPeriod;
ActivityConfirmed(msg.sender, nextPeriod, _lockedValue);
emit ActivityConfirmed(msg.sender, nextPeriod, _lockedValue);
}
/**
@ -372,16 +389,27 @@ contract MinersEscrow is Issuer {
}
uint256 reward = 0;
if (first != EMPTY_CONFIRMED_PERIOD) {
reward = reward.add(mint(info, first, previousPeriod));
first = EMPTY_CONFIRMED_PERIOD; // TODO check
if (info.confirmedPeriod1 != EMPTY_CONFIRMED_PERIOD &&
info.confirmedPeriod1 < info.confirmedPeriod2) {
reward = reward.add(mint(info, info.confirmedPeriod1, previousPeriod));
info.confirmedPeriod1 = EMPTY_CONFIRMED_PERIOD;
} else if (info.confirmedPeriod2 != EMPTY_CONFIRMED_PERIOD &&
info.confirmedPeriod2 < info.confirmedPeriod1) {
reward = reward.add(mint(info, info.confirmedPeriod2, previousPeriod));
info.confirmedPeriod2 = EMPTY_CONFIRMED_PERIOD;
}
if (last <= previousPeriod) {
reward = reward.add(mint(info, last, previousPeriod));
last = EMPTY_CONFIRMED_PERIOD; // TODO check
if (info.confirmedPeriod2 <= previousPeriod &&
info.confirmedPeriod2 > info.confirmedPeriod1) {
reward = reward.add(mint(info, info.confirmedPeriod2, previousPeriod));
info.confirmedPeriod2 = EMPTY_CONFIRMED_PERIOD;
} else if (info.confirmedPeriod1 <= previousPeriod &&
info.confirmedPeriod1 > info.confirmedPeriod2) {
reward = reward.add(mint(info, info.confirmedPeriod1, previousPeriod));
info.confirmedPeriod1 = EMPTY_CONFIRMED_PERIOD;
}
info.value = info.value.add(reward);
Mined(msg.sender, previousPeriod, reward);
emit Mined(msg.sender, previousPeriod, reward);
}
/**
@ -390,7 +418,6 @@ contract MinersEscrow is Issuer {
function mint(MinerInfo storage info, uint256 period, uint256 previousPeriod)
internal returns (uint256 reward)
{
uint256 reward = 0;
uint256 amount;
for (uint256 i = 0; i < info.stakes.length; i++) {
StakeInfo storage stake = info.stakes[i];
@ -400,14 +427,14 @@ contract MinersEscrow is Issuer {
previousPeriod,
stake.lockedValue,
lockedPerPeriod[period],
stake.lastPeriod.sub(period).add(uint256(1)),
stake.lastPeriod.sub(period),
info.decimals);
reward = reward.add(amount);
}
}
// TODO remove if
if (address(policyManager) != 0x0) {
policyManager.updateReward(msg.sender, first);
policyManager.updateReward(msg.sender, period);
}
}
@ -440,10 +467,10 @@ contract MinersEscrow is Issuer {
address current = miners[i];
MinerInfo storage info = minerInfo[current];
if (info.confirmedPeriod1 != currentPeriod &&
info.confirmedPeriod2 == currentPeriod) {
info.confirmedPeriod2 != currentPeriod) {
continue;
}
uint256 lockedTokens = getLockedTokens(current, periods);
uint256 lockedTokens = getLockedTokens(current, _periods);
if (_delta < distance.add(lockedTokens)) {
stop = current;
stopIndex = i;
@ -521,8 +548,8 @@ contract MinersEscrow is Issuer {
function verifyState(address _testTarget) public onlyOwner {
super.verifyState(_testTarget);
require(uint256(delegateGet(_testTarget, "minReleasePeriods()")) ==
minReleasePeriods);
require(uint256(delegateGet(_testTarget, "minLockedPeriods()")) ==
minLockedPeriods);
require(uint256(delegateGet(_testTarget, "minAllowableLockedTokens()")) ==
minAllowableLockedTokens);
require(uint256(delegateGet(_testTarget, "maxAllowableLockedTokens()")) ==
@ -550,17 +577,17 @@ contract MinersEscrow is Issuer {
bytes32(uint8(MinerInfoField.StakesLength)), miner, 0)) == info.stakes.length);
for (uint256 i = 0; i < info.stakes.length && i < MAX_CHECKED_VALUES; i++) {
require(uint256(delegateGet(_testTarget, "getMinerInfo(uint8,address,uint256)",
bytes32(uint8(MinerInfoField.StakeFirstPeriod)), miner, i)) == info.stakes[i].firstPeriod);
bytes32(uint8(MinerInfoField.StakeFirstPeriod)), miner, bytes32(i))) == info.stakes[i].firstPeriod);
require(uint256(delegateGet(_testTarget, "getMinerInfo(uint8,address,uint256)",
bytes32(uint8(MinerInfoField.StakeLastPeriod)), miner, i)) == info.stakes[i].lastPeriod);
bytes32(uint8(MinerInfoField.StakeLastPeriod)), miner, bytes32(i))) == info.stakes[i].lastPeriod);
require(uint256(delegateGet(_testTarget, "getMinerInfo(uint8,address,uint256)",
bytes32(uint8(MinerInfoField.StakeLockedValue)), miner, i)) == info.stakes[i].lockedValue);
bytes32(uint8(MinerInfoField.StakeLockedValue)), miner, bytes32(i))) == info.stakes[i].lockedValue);
}
require(uint256(delegateGet(_testTarget, "getMinerInfo(uint8,address,uint256)",
bytes32(uint8(MinerInfoField.ConfirmedPeriod1)), miner, 0)) == confirmedPeriod1);
bytes32(uint8(MinerInfoField.ConfirmedPeriod1)), miner, 0)) == info.confirmedPeriod1);
require(uint256(delegateGet(_testTarget, "getMinerInfo(uint8,address,uint256)",
bytes32(uint8(MinerInfoField.ConfirmedPeriod2)), miner, 0)) == confirmedPeriod2);
bytes32(uint8(MinerInfoField.ConfirmedPeriod2)), miner, 0)) == info.confirmedPeriod2);
require(uint256(delegateGet(_testTarget, "getMinerInfo(uint8,address,uint256)",
bytes32(uint8(MinerInfoField.LastActivePeriod)), miner, 0)) == info.lastActivePeriod);
@ -585,7 +612,7 @@ contract MinersEscrow is Issuer {
super.finishUpgrade(_target);
MinersEscrow escrow = MinersEscrow(_target);
policyManager = escrow.policyManager();
minReleasePeriods = escrow.minReleasePeriods();
minLockedPeriods = escrow.minLockedPeriods();
minAllowableLockedTokens = escrow.minAllowableLockedTokens();
maxAllowableLockedTokens = escrow.maxAllowableLockedTokens();

View File

@ -20,7 +20,7 @@ contract NuCypherKMSToken is StandardToken, DetailedERC20('NuCypher KMS', 'KMS',
constructor (uint256 _initialAmount) public {
balances[msg.sender] = _initialAmount;
totalSupply_ = _initialAmount;
Transfer(0x0, msg.sender, _initialAmount);
emit Transfer(0x0, msg.sender, _initialAmount);
}
/**

View File

@ -22,7 +22,13 @@ contract UserEscrow is Ownable {
event DepositedAsMiner(address indexed owner, uint256 value, uint256 periods);
event WithdrawnAsMiner(address indexed owner, uint256 value);
event Locked(address indexed owner, uint256 value, uint256 periods);
event LockSwitched(address indexed owner);
event Divided(
address indexed owner,
uint256 oldValue,
uint256 lastPeriod,
uint256 newValue,
uint256 periods
);
event ActivityConfirmed(address indexed owner);
event Mined(address indexed owner);
event RewardWithdrawnAsMiner(address indexed owner, uint256 value);
@ -96,7 +102,7 @@ contract UserEscrow is Ownable {
/**
* @notice Deposit tokens to the miners escrow
* @param _value Amount of token to deposit
* @param _periods Amount of periods during which tokens will be unlocked
* @param _periods Amount of periods during which tokens will be locked
**/
function minerDeposit(uint256 _value, uint256 _periods) public onlyOwner {
require(token.balanceOf(address(this)) > _value);
@ -117,19 +123,30 @@ contract UserEscrow is Ownable {
/**
* @notice Lock some tokens or increase lock in the miners escrow
* @param _value Amount of tokens which should lock
* @param _periods Amount of periods during which tokens will be unlocked
* @param _periods Amount of periods during which tokens will be locked
**/
function lock(uint256 _value, uint256 _periods) public onlyOwner {
escrow.lock(_value, _periods);
emit Locked( owner, _value, _periods);
emit Locked(owner, _value, _periods);
}
/**
* @notice Switch lock in the miners escrow
* @notice Divide stake into two parts
* @param _oldValue Old stake value
* @param _lastPeriod Last period of stake
* @param _newValue New stake value
* @param _periods Amount of periods for extending stake
**/
function switchLock() public onlyOwner {
escrow.switchLock();
emit LockSwitched(owner);
function divideStake(
uint256 _oldValue,
uint256 _lastPeriod,
uint256 _newValue,
uint256 _periods
)
public onlyOwner
{
escrow.divideStake(_oldValue, _lastPeriod, _newValue, _periods);
emit Divided(owner, _oldValue, _lastPeriod, _newValue, _periods);
}
/**
@ -152,16 +169,16 @@ contract UserEscrow is Ownable {
* @notice Withdraw available reward from the policy manager to the user escrow
**/
function policyRewardWithdraw() public onlyOwner {
uint256 balance = this.balance;
uint256 balance = address(this).balance;
policyManager.withdraw();
emit RewardWithdrawnAsMiner(owner, this.balance - balance);
emit RewardWithdrawnAsMiner(owner, address(this).balance - balance);
}
/**
* @notice Withdraw available reward to the owner
**/
function rewardWithdraw() public onlyOwner {
uint256 balance = this.balance;
uint256 balance = address(this).balance;
require(balance != 0);
owner.transfer(balance);
emit RewardWithdrawn(owner, balance);

View File

@ -15,7 +15,6 @@ contract MinersEscrowForUserEscrowMock {
uint256 public lockedValue;
uint256 public periods;
uint256 public confirmedPeriod;
bool public unlock;
constructor(NuCypherKMSToken _token) public {
token = _token;
@ -26,7 +25,6 @@ contract MinersEscrowForUserEscrowMock {
value = _value;
lockedValue = _value;
periods = _periods;
unlock = false;
token.transferFrom(msg.sender, address(this), _value);
}
@ -36,9 +34,17 @@ contract MinersEscrowForUserEscrowMock {
periods += _periods;
}
function switchLock() public {
require(node == msg.sender);
unlock = !unlock;
function divideStake(
uint256 _oldValue,
uint256 _lastPeriod,
uint256 _newValue,
uint256 _periods
)
public
{
require(node == msg.sender && lockedValue == _oldValue && periods == _lastPeriod);
lockedValue += _newValue;
periods += _periods;
}
function withdraw(uint256 _value) public {

View File

@ -7,8 +7,8 @@ pragma solidity ^0.4.18;
contract PolicyManagerForUserEscrowMock {
function withdraw() public {
require(this.balance > 0);
msg.sender.transfer(this.balance);
require(address(this).balance > 0);
msg.sender.transfer(address(this).balance);
}
function () public payable {}

View File

@ -8,19 +8,18 @@ MINERS_LENGTH = 0
MINER = 1
VALUE_FIELD = 2
DECIMALS_FIELD = 3
LOCKED_VALUE_FIELD = 4
RELEASE_FIELD = 5
MAX_RELEASE_PERIODS_FIELD = 6
RELEASE_RATE_FIELD = 7
CONFIRMED_PERIODS_FIELD_LENGTH = 8
CONFIRMED_PERIOD_FIELD = 9
CONFIRMED_PERIOD_LOCKED_VALUE_FIELD = 10
LAST_ACTIVE_PERIOD_FIELD = 11
DOWNTIME_FIELD_LENGTH = 12
DOWNTIME_START_PERIOD_FIELD = 13
DOWNTIME_END_PERIOD_FIELD = 14
MINER_IDS_FIELD_LENGTH = 15
MINER_ID_FIELD = 16
STAKES_FIELD_LENGTH = 4
STAKE_FIRST_PERIOD_FIELD = 5
STAKE_LAST_PERIOD_FIELD = 6
STAKE_LOCKED_VALUE_FIELD = 7
LAST_ACTIVE_PERIOD_FIELD = 8
DOWNTIME_FIELD_LENGTH = 9
DOWNTIME_START_PERIOD_FIELD = 10
DOWNTIME_END_PERIOD_FIELD = 11
MINER_IDS_FIELD_LENGTH = 12
MINER_ID_FIELD = 13
CONFIRMED_PERIOD_1_FIELD = 14
CONFIRMED_PERIOD_2_FIELD = 15
CLIENT_FIELD = 0
INDEX_OF_DOWNTIME_PERIODS_FIELD = 1
@ -30,6 +29,7 @@ RATE_FIELD = 4
START_PERIOD_FIELD = 5
LAST_PERIOD_FIELD = 6
DISABLED_FIELD = 7
FIRST_REWARD_FIELD = 8
REWARD_FIELD = 0
REWARD_RATE_FIELD = 1
@ -194,8 +194,10 @@ def test_all(web3, chain, token, escrow, policy_manager):
chain.wait_for_receipt(tx)
assert reward + 1000 == token.call().balanceOf(escrow.address)
assert 1000 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula2, 0))
assert 1000 == escrow.call().getLockedTokens(ursula2)
assert 10 == web3.toInt(escrow.call().getMinerInfo(MAX_RELEASE_PERIODS_FIELD, ursula2, 0))
assert 0 == escrow.call().getLockedTokens(ursula2)
assert 1000 == escrow.call().getLockedTokens(ursula2, 1)
assert 1000 == escrow.call().getLockedTokens(ursula2, 10)
assert 0 == escrow.call().getLockedTokens(ursula2, 11)
# Can't pre-deposit tokens again for same owner
with pytest.raises(TransactionFailed):
@ -218,19 +220,20 @@ def test_all(web3, chain, token, escrow, policy_manager):
chain.wait_for_receipt(tx)
assert reward + 2000 == token.call().balanceOf(escrow.address)
assert 9000 == token.call().balanceOf(ursula1)
assert 1000 == escrow.call().getLockedTokens(ursula1)
assert 1000 == escrow.call().calculateLockedTokens(ursula1, 1)
assert 1000 == escrow.call().calculateLockedTokens(ursula1, 2)
assert 0 == escrow.call().getLockedTokens(ursula1)
assert 1000 == escrow.call().getLockedTokens(ursula1, 1)
assert 1000 == escrow.call().getLockedTokens(ursula1, 10)
assert 0 == escrow.call().getLockedTokens(ursula1, 11)
# Wait 1 period and deposit from one more Ursula
chain.wait_time(hours=1)
tx = user_escrow_1.transact({'from': ursula3}).minerDeposit(1000, 10)
chain.wait_for_receipt(tx)
assert 1000 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, user_escrow_1.address, 0))
assert 1000 == escrow.call().getLockedTokens(user_escrow_1.address)
assert 10 == web3.toInt(
escrow.call().getMinerInfo(MAX_RELEASE_PERIODS_FIELD, user_escrow_1.address, 0))
assert 0 == web3.toInt(escrow.call().getMinerInfo(RELEASE_FIELD, user_escrow_1.address, 0))
assert 0 == escrow.call().getLockedTokens(user_escrow_1.address)
assert 1000 == escrow.call().getLockedTokens(user_escrow_1.address, 1)
assert 1000 == escrow.call().getLockedTokens(user_escrow_1.address, 10)
assert 0 == escrow.call().getLockedTokens(user_escrow_1.address, 11)
assert reward + 3000 == token.call().balanceOf(escrow.address)
assert 9000 == token.call().balanceOf(user_escrow_1.address)
@ -243,6 +246,14 @@ def test_all(web3, chain, token, escrow, policy_manager):
tx = user_escrow_1.transact({'from': ursula3}).minerDeposit(10000, 5)
chain.wait_for_receipt(tx)
# Divide stakes
tx = escrow.transact({'from': ursula2}).divideStake(1000, escrow.call().getCurrentPeriod() + 9, 500, 9)
chain.wait_for_receipt(tx)
tx = escrow.transact({'from': ursula1}).divideStake(1000, escrow.call().getCurrentPeriod() + 9, 500, 9)
chain.wait_for_receipt(tx)
tx = user_escrow_1.transact({'from': ursula3}).divideStake(1000, escrow.call().getCurrentPeriod() + 10, 500, 8)
chain.wait_for_receipt(tx)
# Confirm activity
tx = escrow.transact({'from': ursula1}).confirmActivity()
chain.wait_for_receipt(tx)
@ -379,13 +390,6 @@ def test_all(web3, chain, token, escrow, policy_manager):
chain.wait_for_receipt(tx)
assert alice2_balance < web3.eth.getBalance(alice2)
tx = escrow.transact({'from': ursula1}).switchLock()
chain.wait_for_receipt(tx)
tx = escrow.transact({'from': ursula2}).switchLock()
chain.wait_for_receipt(tx)
tx = user_escrow_1.transact({'from': ursula3}).switchLock()
chain.wait_for_receipt(tx)
# Unlock and withdraw all tokens in MinersEscrow
for index in range(9):
tx = escrow.transact({'from': ursula1}).confirmActivity()

View File

@ -8,19 +8,18 @@ MINERS_LENGTH = 0
MINER = 1
VALUE_FIELD = 2
DECIMALS_FIELD = 3
LOCKED_VALUE_FIELD = 4
RELEASE_FIELD = 5
MAX_RELEASE_PERIODS_FIELD = 6
RELEASE_RATE_FIELD = 7
CONFIRMED_PERIODS_FIELD_LENGTH = 8
CONFIRMED_PERIOD_FIELD = 9
CONFIRMED_PERIOD_LOCKED_VALUE_FIELD = 10
LAST_ACTIVE_PERIOD_FIELD = 11
DOWNTIME_FIELD_LENGTH = 12
DOWNTIME_START_PERIOD_FIELD = 13
DOWNTIME_END_PERIOD_FIELD = 14
MINER_IDS_FIELD_LENGTH = 15
MINER_ID_FIELD = 16
STAKES_FIELD_LENGTH = 4
STAKE_FIRST_PERIOD_FIELD = 5
STAKE_LAST_PERIOD_FIELD = 6
STAKE_LOCKED_VALUE_FIELD = 7
LAST_ACTIVE_PERIOD_FIELD = 8
DOWNTIME_FIELD_LENGTH = 9
DOWNTIME_START_PERIOD_FIELD = 10
DOWNTIME_END_PERIOD_FIELD = 11
MINER_IDS_FIELD_LENGTH = 12
MINER_ID_FIELD = 13
CONFIRMED_PERIOD_1_FIELD = 14
CONFIRMED_PERIOD_2_FIELD = 15
@pytest.fixture()
@ -60,7 +59,7 @@ def test_escrow(web3, chain, token, escrow_contract):
deposit_log = escrow.eventFilter('Deposited')
lock_log = escrow.eventFilter('Locked')
activity_log = escrow.eventFilter('ActivityConfirmed')
switching_lock_log = escrow.eventFilter('LockSwitched')
divides_log = escrow.eventFilter('Divided')
withdraw_log = escrow.eventFilter('Withdrawn')
# Give Ursula and Ursula(2) some coins
@ -107,33 +106,38 @@ def test_escrow(web3, chain, token, escrow_contract):
with pytest.raises(TransactionFailed):
tx = escrow.transact({'from': ursula1}).deposit(1, 1)
chain.wait_for_receipt(tx)
# And can't deposit and lock too high value
with pytest.raises(TransactionFailed):
tx = escrow.transact({'from': ursula1}).deposit(1501, 1)
chain.wait_for_receipt(tx)
# And can't deposit for too short a period
with pytest.raises(TransactionFailed):
tx = escrow.transact({'from': ursula1}).deposit(1000, 1)
chain.wait_for_receipt(tx)
# Ursula and Ursula(2) transfer some tokens to the escrow and lock them
tx = escrow.transact({'from': ursula1}).deposit(1000, 1)
tx = escrow.transact({'from': ursula1}).deposit(1000, 2)
chain.wait_for_receipt(tx)
assert 1000 == token.call().balanceOf(escrow.address)
assert 9000 == token.call().balanceOf(ursula1)
assert 1000 == escrow.call().getLockedTokens(ursula1)
assert 1000 == escrow.call().calculateLockedTokens(ursula1, 1)
assert 1000 == escrow.call().calculateLockedTokens(ursula1, 2)
assert 0 == escrow.call().getLockedTokens(ursula1)
assert 1000 == escrow.call().getLockedTokens(ursula1, 1)
assert 1000 == escrow.call().getLockedTokens(ursula1, 2)
assert 0 == escrow.call().getLockedTokens(ursula1, 3)
events = deposit_log.get_all_entries()
assert 1 == len(events)
event_args = events[0]['args']
assert ursula1 == event_args['owner']
assert 1000 == event_args['value']
assert 1 == event_args['periods']
assert 2 == event_args['periods']
events = lock_log.get_all_entries()
assert 1 == len(events)
event_args = events[0]['args']
assert ursula1 == event_args['owner']
assert 1000 == event_args['value']
assert 500 == event_args['releaseRate']
assert escrow.call().getCurrentPeriod() + 1 == event_args['firstPeriod']
assert escrow.call().getCurrentPeriod() + 2 == event_args['lastPeriod']
events = activity_log.get_all_entries()
assert 1 == len(events)
event_args = events[0]['args']
@ -141,43 +145,26 @@ def test_escrow(web3, chain, token, escrow_contract):
assert escrow.call().getCurrentPeriod() + 1 == event_args['period']
assert 1000 == event_args['value']
tx = escrow.transact({'from': ursula1}).switchLock()
chain.wait_for_receipt(tx)
assert 500 == escrow.call().calculateLockedTokens(ursula1, 2)
events = switching_lock_log.get_all_entries()
assert 1 == len(events)
event_args = events[0]['args']
assert ursula1 == event_args['owner']
assert event_args['release']
tx = escrow.transact({'from': ursula1}).switchLock()
chain.wait_for_receipt(tx)
assert 1000 == escrow.call().calculateLockedTokens(ursula1, 2)
events = switching_lock_log.get_all_entries()
assert 2 == len(events)
event_args = events[1]['args']
assert ursula1 == event_args['owner']
assert not event_args['release']
tx = escrow.transact({'from': ursula2}).deposit(500, 2)
tx = escrow.transact({'from': ursula2}).deposit(500, 6)
chain.wait_for_receipt(tx)
assert 1500 == token.call().balanceOf(escrow.address)
assert 9500 == token.call().balanceOf(ursula2)
assert 500 == escrow.call().getLockedTokens(ursula2)
assert 500 == escrow.call().calculateLockedTokens(ursula2, 1)
assert 0 == escrow.call().getLockedTokens(ursula2)
assert 500 == escrow.call().getLockedTokens(ursula2, 1)
events = deposit_log.get_all_entries()
assert 2 == len(events)
event_args = events[1]['args']
assert ursula2 == event_args['owner']
assert 500 == event_args['value']
assert 2 == event_args['periods']
assert 6 == event_args['periods']
events = lock_log.get_all_entries()
assert 2 == len(events)
event_args = events[1]['args']
assert ursula2 == event_args['owner']
assert 500 == event_args['value']
assert 250 == event_args['releaseRate']
assert escrow.call().getCurrentPeriod() + 1 == event_args['firstPeriod']
assert escrow.call().getCurrentPeriod() + 6 == event_args['lastPeriod']
events = activity_log.get_all_entries()
assert 2 == len(events)
event_args = events[1]['args']
@ -208,7 +195,7 @@ def test_escrow(web3, chain, token, escrow_contract):
assert escrow.call().getCurrentPeriod() + 1 == event_args['period']
assert 1000 == event_args['value']
tx = escrow.transact({'from': ursula1}).deposit(500, 0)
tx = escrow.transact({'from': ursula1}).deposit(500, 2)
chain.wait_for_receipt(tx)
assert 2000 == token.call().balanceOf(escrow.address)
assert 8500 == token.call().balanceOf(ursula1)
@ -217,18 +204,13 @@ def test_escrow(web3, chain, token, escrow_contract):
event_args = events[3]['args']
assert ursula1 == event_args['owner']
assert escrow.call().getCurrentPeriod() + 1 == event_args['period']
assert 1500 == event_args['value']
assert 500 == event_args['value']
# But can't deposit too high value
with pytest.raises(TransactionFailed):
tx = escrow.transact({'from': ursula1}).deposit(1, 0)
tx = escrow.transact({'from': ursula1}).deposit(1, 2)
chain.wait_for_receipt(tx)
# Ursula starts unlocking
tx = escrow.transact({'from': ursula1}).switchLock()
chain.wait_for_receipt(tx)
assert 750 == escrow.call().calculateLockedTokens(ursula1, 2)
# Wait 1 period and checks locking
chain.wait_time(hours=1)
assert 1500 == escrow.call().getLockedTokens(ursula1)
@ -237,8 +219,15 @@ def test_escrow(web3, chain, token, escrow_contract):
tx = escrow.transact({'from': ursula1}).confirmActivity()
chain.wait_for_receipt(tx)
chain.wait_time(hours=1)
assert 750 == escrow.call().getLockedTokens(ursula1)
assert 0 == escrow.call().calculateLockedTokens(ursula1, 1)
assert 500 == escrow.call().getLockedTokens(ursula1)
assert 0 == escrow.call().getLockedTokens(ursula1, 1)
events = activity_log.get_all_entries()
assert 5 == len(events)
event_args = events[4]['args']
assert ursula1 == event_args['owner']
assert escrow.call().getCurrentPeriod() == event_args['period']
assert 500 == event_args['value']
# And Ursula can withdraw some tokens
tx = escrow.transact({'from': ursula1}).withdraw(100)
@ -262,67 +251,128 @@ def test_escrow(web3, chain, token, escrow_contract):
chain.wait_for_receipt(tx)
# Ursula can deposit and lock more tokens
tx = escrow.transact({'from': ursula1}).deposit(500, 0)
tx = escrow.transact({'from': ursula1}).deposit(500, 2)
chain.wait_for_receipt(tx)
tx = escrow.transact({'from': ursula1}).lock(100, 0)
events = activity_log.get_all_entries()
assert 6 == len(events)
event_args = events[5]['args']
assert ursula1 == event_args['owner']
assert escrow.call().getCurrentPeriod() + 1 == event_args['period']
assert 500 == event_args['value']
tx = escrow.transact({'from': ursula1}).lock(100, 2)
chain.wait_for_receipt(tx)
events = activity_log.get_all_entries()
assert 7 == len(events)
event_args = events[6]['args']
assert ursula1 == event_args['owner']
assert escrow.call().getCurrentPeriod() + 1 == event_args['period']
assert 100 == event_args['value']
# Locked tokens will be updated in next period
# Release rate will be updated too because of the end of previous locking
assert 750 == escrow.call().getLockedTokens(ursula1)
assert 600 == escrow.call().calculateLockedTokens(ursula1, 1)
assert 600 == escrow.call().calculateLockedTokens(ursula1, 2)
tx = escrow.transact({'from': ursula1}).switchLock()
chain.wait_for_receipt(tx)
assert 300 == escrow.call().calculateLockedTokens(ursula1, 2)
assert 0 == escrow.call().calculateLockedTokens(ursula1, 3)
assert 500 == escrow.call().getLockedTokens(ursula1)
assert 600 == escrow.call().getLockedTokens(ursula1, 1)
assert 600 == escrow.call().getLockedTokens(ursula1, 2)
assert 0 == escrow.call().getLockedTokens(ursula1, 3)
chain.wait_time(hours=1)
assert 600 == escrow.call().getLockedTokens(ursula1)
assert 300 == escrow.call().calculateLockedTokens(ursula1, 1)
assert 0 == escrow.call().calculateLockedTokens(ursula1, 2)
assert 600 == escrow.call().getLockedTokens(ursula1, 1)
assert 0 == escrow.call().getLockedTokens(ursula1, 2)
# Ursula can increase lock
tx = escrow.transact({'from': ursula1}).lock(500, 2)
chain.wait_for_receipt(tx)
assert 600 == escrow.call().getLockedTokens(ursula1)
assert 800 == escrow.call().calculateLockedTokens(ursula1, 1)
assert 500 == escrow.call().calculateLockedTokens(ursula1, 2)
assert 200 == escrow.call().calculateLockedTokens(ursula1, 3)
assert 0 == escrow.call().calculateLockedTokens(ursula1, 4)
assert 1100 == escrow.call().getLockedTokens(ursula1, 1)
assert 500 == escrow.call().getLockedTokens(ursula1, 2)
assert 0 == escrow.call().getLockedTokens(ursula1, 3)
chain.wait_time(hours=1)
assert 800 == escrow.call().getLockedTokens(ursula1)
assert 1100 == escrow.call().getLockedTokens(ursula1)
# Ursula(2) starts unlocking and increases lock by deposit more tokens
tx = escrow.transact({'from': ursula2}).deposit(500, 0)
# Ursula(2) increases lock by deposit more tokens
tx = escrow.transact({'from': ursula2}).deposit(500, 2)
chain.wait_for_receipt(tx)
tx = escrow.transact({'from': ursula2}).switchLock()
chain.wait_for_receipt(tx)
assert 1000 == escrow.call().getLockedTokens(ursula2)
assert 1000 == escrow.call().calculateLockedTokens(ursula2, 1)
assert 500 == escrow.call().calculateLockedTokens(ursula2, 2)
assert 0 == escrow.call().calculateLockedTokens(ursula2, 3)
assert 500 == escrow.call().getLockedTokens(ursula2)
assert 1000 == escrow.call().getLockedTokens(ursula2, 1)
assert 500 == escrow.call().getLockedTokens(ursula2, 2)
assert 0 == escrow.call().getLockedTokens(ursula2, 3)
chain.wait_time(hours=1)
assert 1000 == escrow.call().getLockedTokens(ursula2)
# And increases locked time
tx = escrow.transact({'from': ursula2}).lock(0, 2)
tx = escrow.transact({'from': ursula2}).divideStake(500, escrow.call().getCurrentPeriod() + 1, 200, 1)
chain.wait_for_receipt(tx)
assert 1000 == escrow.call().getLockedTokens(ursula2)
assert 500 == escrow.call().calculateLockedTokens(ursula2, 1)
assert 0 == escrow.call().calculateLockedTokens(ursula2, 2)
assert 500 == escrow.call().getLockedTokens(ursula2, 1)
assert 200 == escrow.call().getLockedTokens(ursula2, 2)
assert 0 == escrow.call().getLockedTokens(ursula2, 3)
# Ursula(2) increases lock by small amount of tokens
tx = escrow.transact({'from': ursula2}).deposit(100, 0)
events = lock_log.get_all_entries()
assert 8 == len(events)
event_args = events[7]['args']
assert ursula2 == event_args['owner']
assert 200 == event_args['value']
assert escrow.call().getCurrentPeriod() == event_args['firstPeriod']
assert escrow.call().getCurrentPeriod() + 2 == event_args['lastPeriod']
events = divides_log.get_all_entries()
assert 1 == len(events)
event_args = events[0]['args']
assert ursula2 == event_args['owner']
assert 500 == event_args['oldValue']
assert escrow.call().getCurrentPeriod() + 1 == event_args['lastPeriod']
assert 200 == event_args['newValue']
assert 1 == event_args['periods']
tx = escrow.transact({'from': ursula2}).divideStake(300, escrow.call().getCurrentPeriod() + 1, 200, 1)
chain.wait_for_receipt(tx)
assert 600 == escrow.call().calculateLockedTokens(ursula2, 1)
assert 100 == escrow.call().calculateLockedTokens(ursula2, 2)
assert 0 == escrow.call().calculateLockedTokens(ursula2, 3)
assert 1000 == escrow.call().getLockedTokens(ursula2)
assert 500 == escrow.call().getLockedTokens(ursula2, 1)
assert 400 == escrow.call().getLockedTokens(ursula2, 2)
assert 0 == escrow.call().getLockedTokens(ursula2, 3)
assert 6 == len(deposit_log.get_all_entries())
assert 9 == len(lock_log.get_all_entries())
assert 5 == len(switching_lock_log.get_all_entries())
events = divides_log.get_all_entries()
assert 2 == len(events)
event_args = events[1]['args']
assert ursula2 == event_args['owner']
assert 300 == event_args['oldValue']
assert escrow.call().getCurrentPeriod() + 1 == event_args['lastPeriod']
assert 200 == event_args['newValue']
assert 1 == event_args['periods']
tx = escrow.transact({'from': ursula2}).divideStake(200, escrow.call().getCurrentPeriod() + 2, 100, 1)
chain.wait_for_receipt(tx)
assert 1000 == escrow.call().getLockedTokens(ursula2)
assert 500 == escrow.call().getLockedTokens(ursula2, 1)
assert 400 == escrow.call().getLockedTokens(ursula2, 2)
assert 100 == escrow.call().getLockedTokens(ursula2, 3)
assert 0 == escrow.call().getLockedTokens(ursula2, 4)
events = divides_log.get_all_entries()
assert 3 == len(events)
event_args = events[2]['args']
assert ursula2 == event_args['owner']
assert 200 == event_args['oldValue']
assert escrow.call().getCurrentPeriod() + 2 == event_args['lastPeriod']
assert 100 == event_args['newValue']
assert 1 == event_args['periods']
chain.wait_time(hours=2)
tx = escrow.transact({'from': ursula2}).confirmActivity()
chain.wait_for_receipt(tx)
events = activity_log.get_all_entries()
assert 10 == len(events)
event_args = events[9]['args']
assert ursula2 == event_args['owner']
assert escrow.call().getCurrentPeriod() + 1 == event_args['period']
assert 100 == event_args['value']
assert 5 == len(deposit_log.get_all_entries())
assert 10 == len(lock_log.get_all_entries())
assert 1 == len(withdraw_log.get_all_entries())
assert 11 == len(activity_log.get_all_entries())
def test_locked_distribution(web3, chain, token, escrow_contract):
@ -386,16 +436,16 @@ def test_locked_distribution(web3, chain, token, escrow_contract):
assert 2 == index_stop
assert 1 == shift
address_stop, index_stop, shift = escrow.call().findCumSum(0, 1, 10)
address_stop, index_stop, shift = escrow.call().findCumSum(0, 1, len(miners))
assert NULL_ADDR != address_stop
assert 0 != shift
address_stop, index_stop, shift = escrow.call().findCumSum(0, 1, 11)
address_stop, index_stop, shift = escrow.call().findCumSum(0, 1, len(miners) + 1)
assert NULL_ADDR == address_stop
assert 0 == index_stop
assert 0 == shift
for index, _ in enumerate(miners[:-1]):
address_stop, index_stop, shift = escrow.call().findCumSum(0, 1, index + 3)
address_stop, index_stop, shift = escrow.call().findCumSum(0, 1, index + 2)
assert miners[index + 1] == address_stop
assert index + 1 == index_stop
assert 1 == shift
@ -416,7 +466,7 @@ def test_mining(web3, chain, token, escrow_contract):
deposit_log = escrow.eventFilter('Deposited')
lock_log = escrow.eventFilter('Locked')
activity_log = escrow.eventFilter('ActivityConfirmed')
switching_lock_log = escrow.eventFilter('LockSwitched')
divides_log = escrow.eventFilter('Divided')
withdraw_log = escrow.eventFilter('Withdrawn')
# Give Escrow tokens for reward and initialize contract
@ -449,15 +499,19 @@ def test_mining(web3, chain, token, escrow_contract):
# Ursula and Ursula(2) give Escrow rights to transfer
tx = token.transact({'from': ursula1}).approve(escrow.address, 2000)
chain.wait_for_receipt(tx)
tx = token.transact({'from': ursula2}).approve(escrow.address, 500)
tx = token.transact({'from': ursula2}).approve(escrow.address, 750)
chain.wait_for_receipt(tx)
# Ursula and Ursula(2) transfer some tokens to the escrow and lock them
tx = escrow.transact({'from': ursula1}).deposit(1000, 1)
tx = escrow.transact({'from': ursula1}).deposit(1000, 2)
chain.wait_for_receipt(tx)
tx = escrow.transact({'from': ursula2}).deposit(500, 2)
chain.wait_for_receipt(tx)
# Ursula divides her stake
tx = escrow.transact({'from': ursula1}).divideStake(1000, escrow.call().getCurrentPeriod() + 2, 500, 1)
chain.wait_for_receipt(tx)
# Using locked tokens starts from next period
assert 0 == escrow.call().getAllLockedTokens()
@ -482,16 +536,15 @@ def test_mining(web3, chain, token, escrow_contract):
tx = escrow.transact({'from': ursula1}).mint()
chain.wait_for_receipt(tx)
tx = escrow.transact({'from': ursula2}).mint()
chain.wait_for_receipt(tx)
assert 1050 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula1, 0))
assert 1046 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula1, 0))
assert 521 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula2, 0))
events = mining_log.get_all_entries()
assert 2 == len(events)
event_args = events[0]['args']
assert ursula1 == event_args['owner']
assert 50 == event_args['value']
assert 46 == event_args['value']
assert escrow.call().getCurrentPeriod() - 1 == event_args['period']
event_args = events[1]['args']
assert ursula2 == event_args['owner']
@ -505,32 +558,37 @@ def test_mining(web3, chain, token, escrow_contract):
assert period == policy_manager.call().getPeriod(ursula2, 0)
# Only Ursula confirm activity for next period
tx = escrow.transact({'from': ursula1}).switchLock()
chain.wait_for_receipt(tx)
tx = escrow.transact({'from': ursula1}).confirmActivity()
chain.wait_for_receipt(tx)
# Ursula can't confirm next period because end of locking
# But Ursula(2) can't because end of locking
with pytest.raises(TransactionFailed):
tx = escrow.transact({'from': ursula2}).confirmActivity()
chain.wait_for_receipt(tx)
# Ursula try to mint again
tx = escrow.transact({'from': ursula1}).mint()
chain.wait_for_receipt(tx)
assert 1046 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula1, 0))
events = mining_log.get_all_entries()
assert 2 == len(events)
# Ursula can't confirm next period
chain.wait_time(hours=1)
assert 500 == escrow.call().getAllLockedTokens()
with pytest.raises(TransactionFailed):
tx = escrow.transact({'from': ursula1}).confirmActivity()
chain.wait_for_receipt(tx)
# But Ursula(2) can
tx = escrow.transact({'from': ursula2}).confirmActivity()
chain.wait_for_receipt(tx)
# Ursula mint tokens for next period
# Ursula mint tokens
chain.wait_time(hours=1)
assert 500 == escrow.call().getAllLockedTokens()
assert 0 == escrow.call().getAllLockedTokens()
tx = escrow.transact({'from': ursula1}).mint()
chain.wait_for_receipt(tx)
# But Ursula(2) can't get reward because she did not confirmed activity
# But Ursula(2) can't get reward because she did not confirm activity
tx = escrow.transact({'from': ursula2}).mint()
chain.wait_for_receipt(tx)
assert 1163 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula1, 0))
assert 1152 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula1, 0))
assert 521 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula2, 0))
assert 3 == policy_manager.call().getPeriodsLength(ursula1)
@ -542,90 +600,52 @@ def test_mining(web3, chain, token, escrow_contract):
assert 3 == len(events)
event_args = events[2]['args']
assert ursula1 == event_args['owner']
assert 113 == event_args['value']
assert 106 == event_args['value']
assert escrow.call().getCurrentPeriod() - 1 == event_args['period']
# Ursula(2) confirm next period and mint tokens
tx = escrow.transact({'from': ursula2}).switchLock()
# Ursula can't confirm and get reward because no locked tokens
tx = escrow.transact({'from': ursula1}).mint()
chain.wait_for_receipt(tx)
tx = escrow.transact({'from': ursula2}).confirmActivity()
assert 1152 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula1, 0))
with pytest.raises(TransactionFailed):
tx = escrow.transact({'from': ursula1}).confirmActivity()
chain.wait_for_receipt(tx)
# Ursula(2) deposits and locks more tokens
tx = escrow.transact({'from': ursula2}).deposit(250, 4)
chain.wait_for_receipt(tx)
chain.wait_time(hours=2)
assert 0 == escrow.call().getAllLockedTokens()
tx = escrow.transact({'from': ursula2}).lock(500, 2)
chain.wait_for_receipt(tx)
# Ursula(2) mint only one period
chain.wait_time(hours=5)
tx = escrow.transact({'from': ursula2}).mint()
chain.wait_for_receipt(tx)
assert 1163 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula1, 0))
assert 634 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula2, 0))
assert 3 == policy_manager.call().getPeriodsLength(ursula1)
assert 3 == policy_manager.call().getPeriodsLength(ursula2)
assert period + 3 == policy_manager.call().getPeriod(ursula2, 1)
assert period + 4 == policy_manager.call().getPeriod(ursula2, 2)
assert 1152 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula1, 0))
assert 842 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula2, 0))
events = mining_log.get_all_entries()
assert 4 == len(events)
event_args = events[3]['args']
assert ursula2 == event_args['owner']
assert 113 == event_args['value']
assert 71 == event_args['value']
assert escrow.call().getCurrentPeriod() - 1 == event_args['period']
# Ursula can't confirm and get reward because no locked tokens
tx = escrow.transact({'from': ursula1}).mint()
chain.wait_for_receipt(tx)
assert 1163 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, ursula1, 0))
with pytest.raises(TransactionFailed):
tx = escrow.transact({'from': ursula1}).confirmActivity()
chain.wait_for_receipt(tx)
# Ursula can lock some tokens again
tx = escrow.transact({'from': ursula1}).lock(500, 4)
chain.wait_for_receipt(tx)
tx = escrow.transact({'from': ursula1}).switchLock()
chain.wait_for_receipt(tx)
assert 500 == escrow.call().getLockedTokens(ursula1)
assert 500 == escrow.call().calculateLockedTokens(ursula1, 1)
assert 375 == escrow.call().calculateLockedTokens(ursula1, 2)
assert 250 == escrow.call().calculateLockedTokens(ursula1, 3)
assert 0 == escrow.call().calculateLockedTokens(ursula1, 5)
# And can increase lock
tx = escrow.transact({'from': ursula1}).lock(100, 0)
chain.wait_for_receipt(tx)
assert 600 == escrow.call().getLockedTokens(ursula1)
assert 600 == escrow.call().calculateLockedTokens(ursula1, 1)
assert 450 == escrow.call().calculateLockedTokens(ursula1, 2)
assert 0 == escrow.call().calculateLockedTokens(ursula1, 5)
tx = escrow.transact({'from': ursula1}).lock(0, 2)
chain.wait_for_receipt(tx)
assert 600 == escrow.call().getLockedTokens(ursula1)
assert 600 == escrow.call().calculateLockedTokens(ursula1, 1)
assert 450 == escrow.call().calculateLockedTokens(ursula1, 2)
assert 0 == escrow.call().calculateLockedTokens(ursula1, 5)
tx = escrow.transact({'from': ursula1}).deposit(800, 1)
chain.wait_for_receipt(tx)
assert 1400 == escrow.call().getLockedTokens(ursula1)
assert 1400 == escrow.call().calculateLockedTokens(ursula1, 1)
assert 1000 == escrow.call().calculateLockedTokens(ursula1, 3)
assert 400 == escrow.call().calculateLockedTokens(ursula1, 6)
assert 0 == escrow.call().calculateLockedTokens(ursula1, 8)
# Ursula(2) can withdraw all
tx = escrow.transact({'from': ursula2}).withdraw(634)
tx = escrow.transact({'from': ursula2}).withdraw(842)
chain.wait_for_receipt(tx)
assert 10134 == token.call().balanceOf(ursula2)
assert 10092 == token.call().balanceOf(ursula2)
events = withdraw_log.get_all_entries()
assert 1 == len(events)
event_args = events[0]['args']
assert ursula2 == event_args['owner']
assert 634 == event_args['value']
assert 842 == event_args['value']
assert 3 == len(deposit_log.get_all_entries())
assert 6 == len(lock_log.get_all_entries())
assert 3 == len(switching_lock_log.get_all_entries())
assert 10 == len(activity_log.get_all_entries())
assert 5 == len(lock_log.get_all_entries())
assert 1 == len(divides_log.get_all_entries())
assert 6 == len(activity_log.get_all_entries())
# TODO test max miners
@ -649,8 +669,10 @@ def test_pre_deposit(web3, chain, token, escrow_contract):
chain.wait_for_receipt(tx)
assert 1000 == token.call().balanceOf(escrow.address)
assert 1000 == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, owner, 0))
assert 1000 == escrow.call().getLockedTokens(owner)
assert 10 == web3.toInt(escrow.call().getMinerInfo(MAX_RELEASE_PERIODS_FIELD, owner, 0))
assert 0 == escrow.call().getLockedTokens(owner)
assert 1000 == escrow.call().getLockedTokens(owner, 1)
assert 1000 == escrow.call().getLockedTokens(owner, 10)
assert 0 == escrow.call().getLockedTokens(owner, 11)
# Can't pre-deposit tokens again for same owner
with pytest.raises(TransactionFailed):
@ -680,9 +702,9 @@ def test_pre_deposit(web3, chain, token, escrow_contract):
assert 2500 == token.call().balanceOf(escrow.address)
for index, owner in enumerate(owners):
assert 100 * (index + 1) == web3.toInt(escrow.call().getMinerInfo(VALUE_FIELD, owner, 0))
assert 100 * (index + 1) == escrow.call().getLockedTokens(owner)
assert 50 * (index + 1) == \
web3.toInt(escrow.call().getMinerInfo(MAX_RELEASE_PERIODS_FIELD, owner, 0))
assert 100 * (index + 1) == escrow.call().getLockedTokens(owner, 1)
assert 100 * (index + 1) == escrow.call().getLockedTokens(owner, 50 * (index + 1))
assert 0 == escrow.call().getLockedTokens(owner, 50 * (index + 1) + 1)
events = deposit_log.get_all_entries()
assert 6 == len(events)
@ -725,13 +747,12 @@ def test_miner_id(web3, chain, token, escrow_contract):
balance = token.call().balanceOf(miner)
tx = token.transact({'from': miner}).approve(escrow.address, balance)
chain.wait_for_receipt(tx)
tx = escrow.transact({'from': miner}).deposit(balance, 1)
tx = escrow.transact({'from': miner}).deposit(balance, 2)
chain.wait_for_receipt(tx)
# Set miner ids
miner_id = os.urandom(32)
tx = escrow.transact({'from': miner}).setMinerId(miner_id)
chain.wait_for_receipt(tx)
assert 1 == web3.toInt(escrow.call().getMinerInfo(MINER_IDS_FIELD_LENGTH, miner, 0))

View File

@ -282,11 +282,11 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
'value': int((0.5 * rate + rate * number_of_periods) * 3),
'gas_price': 0})\
.createPolicy(policy_id_3, number_of_periods, int(0.5 * rate), [node1, node2, node3])
chain.wait.for_receipt(tx)
chain.wait_for_receipt(tx)
assert 3 * value + 1.5 * rate == web3.eth.getBalance(policy_manager.address)
assert client_balance - int(3 * value + 1.5 * rate) == web3.eth.getBalance(client)
assert client == web3.toChecksumAddress(
policy_manager.call().getPolicyInfo(CLIENT_FIELD, policy_id_3, NULL_ADDR))
policy_manager.call().getPolicyInfo(CLIENT_FIELD, policy_id_3, NULL_ADDR)[12:])
assert rate == web3.toInt(
policy_manager.call().getPolicyInfo(RATE_FIELD, policy_id_3, NULL_ADDR))
assert 0.5 * rate == web3.toInt(
@ -307,7 +307,7 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
tx = policy_manager.transact({'from': client, 'gas_price': 0}) \
.revokeArrangement(policy_id_3, node1)
chain.wait.for_receipt(tx)
chain.wait_for_receipt(tx)
assert 2 * value + rate == web3.eth.getBalance(policy_manager.address)
assert client_balance - (2 * value + rate) == web3.eth.getBalance(client)
assert 0 == web3.toInt(
@ -322,7 +322,7 @@ def test_create_revoke(web3, chain, escrow, policy_manager):
assert value + 0.5 * rate == event_args['value']
tx = policy_manager.transact({'from': client, 'gas_price': 0}).revokePolicy(policy_id_3)
chain.wait.for_receipt(tx)
chain.wait_for_receipt(tx)
assert 0 == web3.eth.getBalance(policy_manager.address)
assert client_balance == web3.eth.getBalance(client)
assert 1 == web3.toInt(
@ -404,7 +404,7 @@ def test_reward(web3, chain, escrow, policy_manager):
period += 1
assert 120 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node1, 0))
tx = escrow.transact({'from': node1, 'gas_price': 0}).mint(period, 1)
chain.wait.for_receipt(tx)
chain.wait_for_receipt(tx)
assert 120 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node1, 0))
# Withdraw
@ -422,19 +422,19 @@ def test_reward(web3, chain, escrow, policy_manager):
# Create policy
tx = policy_manager.transact({'from': client, 'value': int(2 * value + rate)}) \
.createPolicy(policy_id_2, number_of_periods, int(0.5 * rate), [node2, node3])
chain.wait.for_receipt(tx)
chain.wait_for_receipt(tx)
# Mint some periods
period = escrow.call().getCurrentPeriod()
tx = escrow.transact({'from': node2, 'gas_price': 0}).mint(period, 5)
chain.wait.for_receipt(tx)
chain.wait_for_receipt(tx)
period += 5
assert 90 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node2, 0))
# Mint more periods
for x in range(6):
tx = escrow.transact({'from': node2, 'gas_price': 0}).mint(period, 1)
chain.wait.for_receipt(tx)
chain.wait_for_receipt(tx)
period += 1
assert 210 == web3.toInt(policy_manager.call().getNodeInfo(REWARD_FIELD, node2, 0))

View File

@ -169,7 +169,6 @@ def test_miner(web3, chain, token, escrow, user_escrow):
assert 1500 == escrow.call().value()
assert 1500 == escrow.call().lockedValue()
assert 5 == escrow.call().periods()
assert not escrow.call().unlock()
assert 11500 == token.call().balanceOf(escrow.address)
assert 500 == token.call().balanceOf(user_escrow.address)
@ -191,7 +190,7 @@ def test_miner(web3, chain, token, escrow, user_escrow):
tx = escrow.transact({'from': user}).lock(100, 1)
chain.wait_for_receipt(tx)
with pytest.raises(TransactionFailed):
tx = escrow.transact({'from': user}).switchLock()
tx = escrow.transact({'from': user}).divideStake(1500, 5, 100, 1)
chain.wait_for_receipt(tx)
with pytest.raises(TransactionFailed):
tx = escrow.transact({'from': user}).confirmActivity()
@ -207,22 +206,23 @@ def test_miner(web3, chain, token, escrow, user_escrow):
chain.wait_for_receipt(tx)
locks = user_escrow.eventFilter('Locked')
switches = user_escrow.eventFilter('LockSwitched')
divides = user_escrow.eventFilter('Divided')
confirms = user_escrow.eventFilter('ActivityConfirmed')
mints = user_escrow.eventFilter('Mined')
miner_withdraws = user_escrow.eventFilter('WithdrawnAsMiner')
withdraws = user_escrow.eventFilter('Withdrawn')
# Use methods through the user escrow
tx = user_escrow.transact({'from': user}).lock(100, 1)
chain.wait_for_receipt(tx)
assert 1500 == escrow.call().value()
assert 1600 == escrow.call().lockedValue()
assert 6 == escrow.call().periods()
tx = user_escrow.transact({'from': user}).switchLock()
tx = user_escrow.transact({'from': user}).divideStake(1600, 6, 100, 1)
chain.wait_for_receipt(tx)
assert escrow.call().unlock()
assert 1500 == escrow.call().value()
assert 1700 == escrow.call().lockedValue()
assert 7 == escrow.call().periods()
tx = user_escrow.transact({'from': user}).confirmActivity()
chain.wait_for_receipt(tx)
assert 1 == escrow.call().confirmedPeriod()
@ -247,10 +247,14 @@ def test_miner(web3, chain, token, escrow, user_escrow):
assert 100 == event_args['value']
assert 1 == event_args['periods']
events = switches.get_all_entries()
events = divides.get_all_entries()
assert 1 == len(events)
event_args = events[0]['args']
assert user == event_args['owner']
assert 1600 == event_args['oldValue']
assert 100 == event_args['newValue']
assert 6 == event_args['lastPeriod']
assert 1 == event_args['periods']
events = confirms.get_all_entries()
assert 1 == len(events)