Remove reference counting for cumulative rewards
This commit is contained in:
@@ -94,9 +94,6 @@ contract MixinStorage is
|
||||
// mapping from Pool Id to Epoch to Reward Ratio
|
||||
mapping (bytes32 => mapping (uint256 => IStructs.Fraction)) internal _cumulativeRewardsByPool;
|
||||
|
||||
// mapping from Pool Id to Epoch to Cumulative Rewards Reference Counter
|
||||
mapping (bytes32 => mapping (uint256 => uint256)) internal _cumulativeRewardsByPoolReferenceCounter;
|
||||
|
||||
// mapping from Pool Id to Epoch
|
||||
mapping (bytes32 => uint256) internal _cumulativeRewardsByPoolLastStored;
|
||||
|
||||
|
||||
@@ -63,30 +63,6 @@ contract MixinCumulativeRewards is
|
||||
return cumulativeReward.denominator != 0;
|
||||
}
|
||||
|
||||
/// @dev Returns true iff the cumulative reward for `poolId` at `epoch` can
|
||||
/// be unset.
|
||||
/// @param poolId Unique id of pool.
|
||||
/// @param epoch Epoch of the cumulative reward.
|
||||
function _canUnsetCumulativeReward(bytes32 poolId, uint256 epoch)
|
||||
internal
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
// Must be a value to unset
|
||||
if (!_isCumulativeRewardSet(_cumulativeRewardsByPool[poolId][epoch])) {
|
||||
return false;
|
||||
}
|
||||
// Must be no references to this CR
|
||||
if (_cumulativeRewardsByPoolReferenceCounter[poolId][epoch] != 0) {
|
||||
return false;
|
||||
}
|
||||
// Must not be the most recently *stored* CR.
|
||||
if (_cumulativeRewardsByPoolLastStored[poolId] == epoch) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Tries to set a cumulative reward for `poolId` at `epoch`.
|
||||
/// @param poolId Unique Id of pool.
|
||||
/// @param epoch Epoch of cumulative reward.
|
||||
@@ -129,27 +105,6 @@ contract MixinCumulativeRewards is
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Tries to unset the cumulative reward for `poolId` at `epoch`.
|
||||
/// @param poolId Unique id of pool.
|
||||
/// @param epoch Epoch of cumulative reward to unset.
|
||||
function _tryUnsetCumulativeReward(bytes32 poolId, uint256 epoch)
|
||||
internal
|
||||
{
|
||||
if (!_canUnsetCumulativeReward(poolId, epoch)) {
|
||||
return;
|
||||
}
|
||||
_forceUnsetCumulativeReward(poolId, epoch);
|
||||
}
|
||||
|
||||
/// @dev Unsets the cumulative reward for `poolId` at `epoch`.
|
||||
/// @param poolId Unique id of pool.
|
||||
/// @param epoch Epoch of cumulative reward to unset.
|
||||
function _forceUnsetCumulativeReward(bytes32 poolId, uint256 epoch)
|
||||
internal
|
||||
{
|
||||
delete _cumulativeRewardsByPool[poolId][epoch];
|
||||
}
|
||||
|
||||
/// @dev Tries to set the epoch of the most recent cumulative reward.
|
||||
/// The value will only be set if the input epoch is greater than the
|
||||
/// current most recent value.
|
||||
@@ -191,37 +146,6 @@ contract MixinCumulativeRewards is
|
||||
// Sanity check that we're not trying to go back in time
|
||||
assert(newMostRecentEpoch >= currentMostRecentEpoch);
|
||||
_cumulativeRewardsByPoolLastStored[poolId] = newMostRecentEpoch;
|
||||
|
||||
// Unset the previous most recent reward, if it is no longer needed
|
||||
_tryUnsetCumulativeReward(poolId, currentMostRecentEpoch);
|
||||
}
|
||||
|
||||
/// @dev Adds a dependency on a cumulative reward for a given epoch.
|
||||
/// @param poolId Unique Id of pool.
|
||||
/// @param epoch Epoch to remove dependency from.
|
||||
/// @param mostRecentCumulativeReward The most recent cumulative reward.
|
||||
/// @param isDependent True iff there is a dependency on the cumulative
|
||||
/// reward for `poolId` at `epoch`
|
||||
function _addOrRemoveDependencyOnCumulativeReward(
|
||||
bytes32 poolId,
|
||||
uint256 epoch,
|
||||
IStructs.Fraction memory mostRecentCumulativeReward,
|
||||
bool isDependent
|
||||
)
|
||||
internal
|
||||
{
|
||||
if (isDependent) {
|
||||
_addDependencyOnCumulativeReward(
|
||||
poolId,
|
||||
epoch,
|
||||
mostRecentCumulativeReward
|
||||
);
|
||||
} else {
|
||||
_removeDependencyOnCumulativeReward(
|
||||
poolId,
|
||||
epoch
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Computes a member's reward over a given epoch interval.
|
||||
@@ -279,44 +203,4 @@ contract MixinCumulativeRewards is
|
||||
uint256 lastStoredEpoch = _cumulativeRewardsByPoolLastStored[poolId];
|
||||
return _cumulativeRewardsByPool[poolId][lastStoredEpoch];
|
||||
}
|
||||
|
||||
/// @dev Adds a dependency on a cumulative reward for a given epoch.
|
||||
/// @param poolId Unique Id of pool.
|
||||
/// @param epoch Epoch to remove dependency from.
|
||||
/// @param mostRecentCumulativeReward The most recent cumulative reward.
|
||||
function _addDependencyOnCumulativeReward(
|
||||
bytes32 poolId,
|
||||
uint256 epoch,
|
||||
IStructs.Fraction memory mostRecentCumulativeReward
|
||||
)
|
||||
private
|
||||
{
|
||||
// Add dependency by increasing the reference counter
|
||||
_cumulativeRewardsByPoolReferenceCounter[poolId][epoch] =
|
||||
_cumulativeRewardsByPoolReferenceCounter[poolId][epoch].safeAdd(1);
|
||||
|
||||
// Set CR to most recent reward (if it is not already set)
|
||||
_trySetCumulativeReward(
|
||||
poolId,
|
||||
epoch,
|
||||
mostRecentCumulativeReward
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Removes a dependency on a cumulative reward for a given epoch.
|
||||
/// @param poolId Unique Id of pool.
|
||||
/// @param epoch Epoch to remove dependency from.
|
||||
function _removeDependencyOnCumulativeReward(
|
||||
bytes32 poolId,
|
||||
uint256 epoch
|
||||
)
|
||||
private
|
||||
{
|
||||
// Remove dependency by decreasing reference counter
|
||||
_cumulativeRewardsByPoolReferenceCounter[poolId][epoch] =
|
||||
_cumulativeRewardsByPoolReferenceCounter[poolId][epoch].safeSub(1);
|
||||
|
||||
// Clear cumulative reward from state, if it is no longer needed
|
||||
_tryUnsetCumulativeReward(poolId, epoch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,16 +152,7 @@ contract MixinStakingPoolRewards is
|
||||
// epoch, if necessary.
|
||||
_setCumulativeRewardDependenciesForDelegator(
|
||||
poolId,
|
||||
finalDelegatedStakeToPoolByOwner,
|
||||
true
|
||||
);
|
||||
|
||||
// Remove dependencies on previous cumulative rewards, if they are no
|
||||
// longer needed.
|
||||
_setCumulativeRewardDependenciesForDelegator(
|
||||
poolId,
|
||||
initialDelegatedStakeToPoolByOwner,
|
||||
false
|
||||
finalDelegatedStakeToPoolByOwner
|
||||
);
|
||||
}
|
||||
|
||||
@@ -387,20 +378,12 @@ contract MixinStakingPoolRewards is
|
||||
/// @param poolId Unique id of pool.
|
||||
/// @param _delegatedStakeToPoolByOwner Amount of stake the member has
|
||||
/// delegated to the pool.
|
||||
/// @param isDependent is true iff adding a dependency. False, otherwise.
|
||||
function _setCumulativeRewardDependenciesForDelegator(
|
||||
bytes32 poolId,
|
||||
IStructs.StoredBalance memory _delegatedStakeToPoolByOwner,
|
||||
bool isDependent
|
||||
IStructs.StoredBalance memory _delegatedStakeToPoolByOwner
|
||||
)
|
||||
private
|
||||
{
|
||||
// If this delegator is not yet initialized then there's no dependency
|
||||
// to unset.
|
||||
if (!isDependent && !_delegatedStakeToPoolByOwner.isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the most recent cumulative reward, which will serve as a
|
||||
// reference point when updating dependencies
|
||||
IStructs.Fraction memory mostRecentCumulativeReward = _getMostRecentCumulativeReward(poolId);
|
||||
@@ -409,21 +392,19 @@ contract MixinStakingPoolRewards is
|
||||
if (_delegatedStakeToPoolByOwner.currentEpochBalance != 0
|
||||
|| _delegatedStakeToPoolByOwner.nextEpochBalance != 0)
|
||||
{
|
||||
_addOrRemoveDependencyOnCumulativeReward(
|
||||
_trySetCumulativeReward(
|
||||
poolId,
|
||||
_delegatedStakeToPoolByOwner.currentEpoch,
|
||||
mostRecentCumulativeReward,
|
||||
isDependent
|
||||
mostRecentCumulativeReward
|
||||
);
|
||||
}
|
||||
|
||||
// Record dependency on the next epoch
|
||||
if (_delegatedStakeToPoolByOwner.nextEpochBalance != 0) {
|
||||
_addOrRemoveDependencyOnCumulativeReward(
|
||||
_trySetCumulativeReward(
|
||||
poolId,
|
||||
uint256(_delegatedStakeToPoolByOwner.currentEpoch).safeAdd(1),
|
||||
mostRecentCumulativeReward,
|
||||
isDependent
|
||||
mostRecentCumulativeReward
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,11 +30,6 @@ contract TestCumulativeRewardTracking is
|
||||
uint256 epoch
|
||||
);
|
||||
|
||||
event UnsetCumulativeReward(
|
||||
bytes32 poolId,
|
||||
uint256 epoch
|
||||
);
|
||||
|
||||
event SetMostRecentCumulativeReward(
|
||||
bytes32 poolId,
|
||||
uint256 epoch
|
||||
@@ -59,13 +54,6 @@ contract TestCumulativeRewardTracking is
|
||||
);
|
||||
}
|
||||
|
||||
function _forceUnsetCumulativeReward(bytes32 poolId, uint256 epoch)
|
||||
internal
|
||||
{
|
||||
emit UnsetCumulativeReward(poolId, epoch);
|
||||
MixinCumulativeRewards._forceUnsetCumulativeReward(poolId, epoch);
|
||||
}
|
||||
|
||||
function _forceSetMostRecentCumulativeRewardEpoch(
|
||||
bytes32 poolId,
|
||||
uint256 currentMostRecentEpoch,
|
||||
|
||||
@@ -78,22 +78,6 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
],
|
||||
);
|
||||
});
|
||||
it('delegating then undelegating in the same epoch', async () => {
|
||||
await simulation.runTestAsync(
|
||||
[
|
||||
// Creates CR for epoch 0
|
||||
TestAction.CreatePool,
|
||||
// Updates CR for epoch 0
|
||||
// Creates CR for epoch 1
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
// Unsets the CR for epoch 1
|
||||
TestAction.Undelegate,
|
||||
],
|
||||
[{ event: 'UnsetCumulativeReward', epoch: 1 }],
|
||||
);
|
||||
});
|
||||
it('delegating in new epoch', async () => {
|
||||
// since there was no delegation in epoch 0 there is no longer a dependency on the CR for epoch 0
|
||||
await simulation.runTestAsync(
|
||||
@@ -113,7 +97,6 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 1 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 1 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 0 },
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
],
|
||||
);
|
||||
@@ -140,32 +123,9 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
{ event: 'SetCumulativeReward', epoch: 1 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 1 },
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 0 },
|
||||
],
|
||||
);
|
||||
});
|
||||
it('delegate then undelegate to remove all dependencies', async () => {
|
||||
await simulation.runTestAsync(
|
||||
[
|
||||
// Creates CR for epoch 0
|
||||
TestAction.CreatePool,
|
||||
// Moves to epoch 1
|
||||
TestAction.Finalize,
|
||||
// Creates CR for epoch 1
|
||||
// Sets MRCR to epoch 1
|
||||
// Clears CR for epoch 0
|
||||
// Creates CR for epoch 2
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
// Clears CR from epoch 2
|
||||
// Does NOT clear CR from epoch 1 because it is the current
|
||||
// epoch.
|
||||
TestAction.Undelegate,
|
||||
],
|
||||
[{ event: 'UnsetCumulativeReward', epoch: 2 }],
|
||||
);
|
||||
});
|
||||
it('delegating in epoch 1 then again in epoch 2', async () => {
|
||||
await simulation.runTestAsync(
|
||||
[
|
||||
@@ -192,7 +152,6 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetCumulativeReward', epoch: 3 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
],
|
||||
);
|
||||
});
|
||||
@@ -217,11 +176,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Clear CR for epoch 1
|
||||
TestAction.Undelegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 2 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 2 }, { event: 'SetMostRecentCumulativeReward', epoch: 2 }],
|
||||
);
|
||||
});
|
||||
it('delegate in epoch 0 and epoch 1, then undelegate half in epoch 2', async () => {
|
||||
@@ -254,7 +209,6 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetCumulativeReward', epoch: 3 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
],
|
||||
);
|
||||
});
|
||||
@@ -288,7 +242,6 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetCumulativeReward', epoch: 3 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
],
|
||||
);
|
||||
});
|
||||
@@ -347,12 +300,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Clears CR for epoch 2
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 3 },
|
||||
{ event: 'SetCumulativeReward', epoch: 4 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 2 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 3 }, { event: 'SetCumulativeReward', epoch: 4 }],
|
||||
);
|
||||
});
|
||||
it('delegate in epoch 0 and 1, earn reward in epoch 3, then undelegate half', async () => {
|
||||
@@ -387,12 +335,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Clears CR for epoch 2
|
||||
TestAction.Undelegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 3 },
|
||||
{ event: 'SetCumulativeReward', epoch: 4 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 2 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 3 }, { event: 'SetCumulativeReward', epoch: 4 }],
|
||||
);
|
||||
});
|
||||
it('delegate in epoch 1, 2, earn rewards in epoch 3, skip to epoch 4, then delegate', async () => {
|
||||
@@ -433,10 +376,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 4 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 4 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 3 },
|
||||
{ event: 'SetCumulativeReward', epoch: 5 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 2 },
|
||||
],
|
||||
);
|
||||
});
|
||||
@@ -461,7 +401,6 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 1 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 1 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 0 },
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
],
|
||||
);
|
||||
@@ -502,7 +441,6 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
{ event: 'SetCumulativeReward', epoch: 4 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 4 },
|
||||
{ event: 'SetCumulativeReward', epoch: 5 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 3 },
|
||||
],
|
||||
);
|
||||
});
|
||||
@@ -535,8 +473,6 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
{ event: 'SetCumulativeReward', epoch: 3 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 3 },
|
||||
{ event: 'SetCumulativeReward', epoch: 4 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 2 },
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
@@ -46,11 +46,6 @@ export class CumulativeRewardTrackingSimulation {
|
||||
event: log.event,
|
||||
epoch: log.args.epoch.toNumber(),
|
||||
});
|
||||
} else if (log.event === TestCumulativeRewardTrackingEvents.UnsetCumulativeReward) {
|
||||
logs.push({
|
||||
event: log.event,
|
||||
epoch: log.args.epoch.toNumber(),
|
||||
});
|
||||
}
|
||||
}
|
||||
return logs;
|
||||
|
||||
Reference in New Issue
Block a user