-
Notifications
You must be signed in to change notification settings - Fork 112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Miner variable rewards I #399
Conversation
be707ca
to
e39a0d7
Compare
49c4730
to
adac96b
Compare
contracts/ColonyNetworkMining.sol
Outdated
@@ -113,29 +114,61 @@ contract ColonyNetworkMining is ColonyNetworkStorage { | |||
} | |||
} | |||
|
|||
function rewardStakers(address[] stakers) internal { | |||
// Constants for miner weight calculations | |||
uint256 constant T = 7776000 * WAD; // Seconds in 90 days |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update comment to be clear it is Seconds in 90 days * WAD
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
contracts/ColonyNetworkMining.sol
Outdated
function rewardStakers(address[] stakers) internal { | ||
// Constants for miner weight calculations | ||
uint256 constant T = 7776000 * WAD; // Seconds in 90 days | ||
uint256 constant N = 24 * WAD; // 2x maximum number of miners |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2x maximum number of miners * WAD
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
contracts/IColonyNetwork.sol
Outdated
/// @param _timeStaked Amount of time (in seconds) that the miner has staked their CLNY | ||
/// @param _submissonIndex Index of reputation hash submission (between 1 and 12) | ||
/// @return minerWeight The weight of miner reward | ||
function calculateMinerWeight(uint256 _timeStaked, uint256 _submissonIndex) public view returns (uint256 minerWeight); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Function can be set to pure
(both here and in the implementation)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -199,12 +199,13 @@ contract IReputationMiningCycle { | |||
|
|||
/// @notice Start the reputation log with the rewards for the stakers who backed the accepted new reputation root hash. | |||
/// @param stakers The array of stakers addresses to receive the reward. | |||
/// @param commonColonyAddress The address of the common colony, which the special mining skill is earned in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aaa we still had this leftover common colony terminology around! Glad you found it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥇
contracts/IReputationMiningCycle.sol
Outdated
/// @param reward The amount of reputation to be rewarded to each staker | ||
/// @dev Only callable by colonyNetwork | ||
/// @dev Note that the same address might be present multiple times in `stakers` - this is acceptable, and indicates the | ||
/// same address backed the same hash multiple times with different entries. | ||
function rewardStakersWithReputation(address[] stakers, address commonColonyAddress, uint reward, uint miningSkillId) public; | ||
function rewardStakersWithReputation(address[] stakers, uint256[] weights, address metaColonyAddress, uint reward, uint miningSkillId) public; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this was there beforehand but can we update the uint
parameters to be explicitly uint256
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
contracts/TokenLocking.sol
Outdated
|
||
uint256 timestamp = add(mul(prevWeight, lock.timestamp), mul(currWeight, now)) / add(prevWeight, currWeight); | ||
|
||
userLocks[_token][msg.sender] = Lock(totalLockCount[_token], add(lock.balance, _amount), timestamp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The above lock
variable is a storage reference so you can set any of it properties directly e.g.
lock.balance = add(lock.balance, _amount);
lock.timestamp = timestamp;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, but since we're setting all of the fields simultaneously it seems justified to do it in one go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see us setting all the fields here, totalLockCount
is not changed just the other two.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hrm, could there be a situation where totalLockCount[_token]
is different than it was when the last deposit was made?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elenadimitrova This test fails if we don't also set totalLockCount[_token]
:
should be able to set user lock count equal to total lock count when depositing if user had 0 deposited tokens:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you're right. Glad I dug in this function to find another issue (#437), unrelated to the changes here.
At least I'd like to reuse the lock storage reference and do
lock = Lock(totalLockCount[_token], add(lock.balance, _amount), newTimestamp);
contracts/ColonyNetworkMining.sol
Outdated
|
||
for (i = 0; i < stakers.length; i++) { | ||
(,,timeStaked) = ITokenLocking(tokenLocking).getUserLock(clnyToken, stakers[i]); | ||
minerWeights[i] = calculateMinerWeight(now - timeStaked, i + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the submissionIndex
in calculateMinerWeight
is 0-based then there won't be need to do i + 1
here and submissionIndex - 1
there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯
@@ -188,7 +190,8 @@ contract ReputationMiningCycle is ReputationMiningCycleStorage, PatriciaTreeProo | |||
IColonyNetwork(colonyNetworkAddress).setReputationRootHash( | |||
submission.proposedNewRootHash, | |||
submission.nNodes, | |||
submittedHashes[submission.proposedNewRootHash][submission.nNodes] | |||
submittedHashes[submission.proposedNewRootHash][submission.nNodes], | |||
1200 * WAD // TODO: Make this a function of reputation state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we avoid going round the houses and passing the reward
to IColonyNetwork. setReputationRootHash
which calls IColonyNetwork.rewardStakers
which in turns circles back to here IReputationMiningCycle.rewardStakersWithReputation
and make it a separate internal contract call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If that 👆 works we'll avoid importing ITokenLocking
in ColonyNetworkMining
too and reuse the import here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rewarding miners with tokens can stay in ColonyNetworkMining
but reputation rewards can likely be done here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. I would say in that case let's move the whole reward flow into ReputationMiningCycle
. Having the reward logic split over two contracts seems unnecessary; we can get metaColonyAddress
via IColonyNetwork(colonyNetworkAddress)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Erm wait, I'm noticing that we're not technically going in a circle -- the original contract is the activeReputationMiningCycle
and we call back into the inactiveReputationMiningCycle
. So this circuitous route is not so circuitous after all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. I still experimented a little with refactoring this but got no significant benefits clarity wise. Considering confirmNewHash
gas cost of 687,823 which is less than a dollar at current prices this isn't a priority atm so happy to leave as is, for now at least.
test/token-locking.js
Outdated
const info2 = await tokenLocking.getUserLock(token.address, userAddress); | ||
|
||
const avgTime = (time1 + time2) / 2; | ||
assert.closeTo(info2[2].toNumber(), avgTime, 1); // Tolerance of 1 second |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test can be made deterministic if you query the most recent block after each deposit, getting the actual timestamp the transaction was executed at.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't there also be tests where the deposit amount is unequal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can do that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
test/colony-network-mining.js
Outdated
assert.isTrue(balance1Updated.sub(REWARD.divn(2)).gtn(0), "Account was not rewarded properly"); | ||
// Less than half of the reward | ||
assert.isTrue(balance2Updated.sub(REWARD.divn(2)).ltn(0), "Account was not rewarded properly"); | ||
// Sum is total reward within 100 wei of precision error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This 100 wei figure is completely arbitrary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was it a conscious decision to only be checking that the total awarded was at least the right amount, rather than no more than the right amount? Are we enable to ensure we always land on one side or the other?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's somewhat arbitrary, as a "very small round number" (although I just tried it with 10 wei and it passed). And I believe that closeTo
test is double-sided, looking for whether the amount is within 100 of the target in either direction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You know, turns out even equal
works. But part of me still prefers to write the test in terms of tolerance, since someone could change the token values later and the test could then fail for unrelated precision reasons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will write test in terms of stakers.length wei
.
contracts/ColonyNetworkMining.sol
Outdated
// Also give them some newly minted tokens. | ||
ERC20Extended(IColony(metaColony).getToken()).transfer(stakers[i], reward); | ||
for (i = 0; i < stakers.length; i++) { | ||
ERC20Extended(clnyToken).transfer(stakers[i], wmul(reward, minerWeights[i])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's going to be some dust left at the end of this, no? Can we explicitly burn it, or something, rather than leaving it in an address that we can't recover it from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's also the issue with rounding up 0.5s with wmul/wdiv... We could calculate how much we should mint, and mint that? But then the total reward is not exactly 1200 CLNY...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mm I like the idea of working backwards to figure out the amount to mint. Saying "we'd like to give out around X CLNY, but given some slight imprecision we're going to figure out what the rewards should be and mint that amount".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm proposing we introduce a realReward
value which is calculated as a sum of the weighted reward
, which avoids dust issues. Given that the reputation amount is meant to be variable anyway (i.e. a function of the reputation state), I think this approach is reasonable for now. If we need stronger guarantees we can circle back around to this issue.
adac96b
to
e198242
Compare
e198242
to
57012e6
Compare
@elenadimitrova @area Have updated in response to feedback |
57012e6
to
058aa3c
Compare
058aa3c
to
2ff6421
Compare
Partially addresses #164