-
Notifications
You must be signed in to change notification settings - Fork 369
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
Implement proof-of-stake changes #1177
Conversation
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.
Got through Governance.sol and LockedGold.sol.
uint128 value; | ||
uint128 index; | ||
struct Authorizations { | ||
// The address that is authorized to vote on behalf of the account. |
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.
Is this always set to something? I imagine if it's 0, the account itself is authorized to vote. If so, might be worth adding info on this edge case to the comment. Ditto below.
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.
Good call, this behavior is unclear, made it more detailed in the comments.
} | ||
|
||
struct Balances { | ||
// This contract does not store an account's locked gold that is being used in electing |
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 feels like a weird location to put this comment - comments above struct fields usually describe what a field represents. This one I guess is more of a "what this field does not represent" comment?
Not sure what a better place would be. Maybe just prefixing it with "NOTE:" would clear up the confusion for me personally?
Also, describing what exactly nonvoting
's value represents might be helpful.
* @param _account The address of the account. | ||
* @param noticePeriod The notice period of the Locked Gold commitment. | ||
* @return The value and index of the specified Locked Gold commitment. | ||
* @notice Withdraws a gold that has been unlocked after the unlocking period has passed. |
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.
Typo: unnecessary "a".
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.
Removed
) | ||
private | ||
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.
Can this be external
?
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.
Sure can
* @param r Output value r of the ECDSA signature. | ||
* @param s Output value s of the ECDSA signature. | ||
* @dev Fails if the address is already authorized or is an account. | ||
* @dev v, r, s constitute `authorize`'s signature on `msg.sender`. |
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 no variable called authorize
. Presume this should be current
?
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.
Danger of search and replace
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.
Got through contracts and migrations, started looking at unit tests.
// minimum amount of Locked Gold required in order to earn epoch rewards. Furthermore, the | ||
// account will not be able to unlock Gold if it would cause the account to fall below | ||
// these values. | ||
// If an account has deregistered a validator or validator group and is still subject to the |
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, this doesn't sound like the best contract for a validator. One could be afraid of a situation in which, after registering, DeregistrationLockup goes up and BalanceRequirements is increased above one's balance. Sounds like with the current setup, a validator's locked funds could be made unexpectedly unavailable to them?
Maybe this is something we just have to live with, rely on the governance process to not have these move unfairly. The other option would be to store historical values per validator and honor the contract they made when registering.
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.
Yup, that's exactly correct. If I, as a validator, lock up more than the required gold, and then the requirement goes up, that extra gold which was previously relatively accessible to me becomes locked up until I deregister and wait out the lockup period.
How comfortable validators are with this I suppose is dependent on their faith in the governance process.
The other option would be to store historical values per validator and honor the contract they made when registering.
This would work, but IMO the ability to adjust the requirements/lockups is a feature and not a bug.
} | ||
|
||
// After deregistering a validator or validator group, the account will remain subject to the | ||
// current balance requirements for this long (in seconds). |
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.
Related to the above, this comment could be read as "whatever the current requirement is at time of deregistration, that is the requirement that will be enforced when trying to unlock", which I believe is not the case, right?
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.
Correct, Validators are subject to whatever the current requirements are. How would you suggest phrasing this?
resp = await election.markGroupIneligible(group) | ||
}) | ||
|
||
describe('when the group has votes', () => {}) |
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.
Empty describe
. Did you mean to put the it
s below inside of 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.
Nope, not sure where this came from
election.revokeActive(group, value + 1, NULL_ADDRESS, NULL_ADDRESS, index) | ||
) | ||
}) | ||
}) |
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.
Agreed. A whole scenario where a voters cast votes, (mock?) rewards are distributed, more voters cast votes, and then ensuring everyone ends up with the correct balance would be nice.
|
||
it('should elect only n members from that group', async () => { | ||
assertSameAddresses(await election.electValidators(), [ | ||
validator7, |
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.
Did you mean to have these out of order?
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 believe they're ordered in the order that they would be elected by d'hondt
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.
final comments. Maybe only one to review, still approving it so can be merged after solving the comments
*/ | ||
|
||
async markGroupEligible(validatorGroup: Address): Promise<CeloTransactionObject<boolean>> { | ||
if (this.kit.defaultAccount == null) { |
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.
no. Maybe add a TODO so it's addresses on another PR
|
||
async markGroupEligible(validatorGroup: Address): Promise<CeloTransactionObject<boolean>> { | ||
if (this.kit.defaultAccount == null) { | ||
throw new Error(`missing from at new ValdidatorUtils()`) |
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.
same... add a todo?
function isValidating(address validator) external view returns (bool) { | ||
IValidators validators = IValidators(registry.getAddressFor(VALIDATORS_REGISTRY_ID)); | ||
return validators.isValidating(validator); | ||
function _decrementNonvotingAccountBalance(address account, uint256 value) private { |
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 though solidity linter expects all internal methods to go after public/external ones
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.
Looks like the new version of solhint has this check disabled by default. I'll reorder these in a follow-up PR to avoid merge conflicts in asaj/pos-2
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.
We can disable that if we want. Not sure what we prefer.
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 think it would be good to enable, the function ordering in my PR is a bit nonsensical and hard to read. Only keeping it this way to minimize merge conflicts with asaj/pos-2
*/ | ||
function getActiveVotesUnitsDelta(address group, uint256 value) private view returns (uint256) { | ||
// Preserve unitsDelta * total = value * totalUnits | ||
return value.mul(votes.active.forGroup[group].totalUnits.add(1)).div( |
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.
Not sure to follow the math here.
So the relation is:
accountUnits / totalUnits = accountValue / totalValue
where value = votes
The question is: how much units would i gain if a add X
value/votes
that means i need to solve this equation:
(newUnits) / (totalUnits + newUnits) = (addedValue) / (totalValue + addedValue)
where we need to get newUnits
and the rest is given.
which doesn't look similar to what we are doing here... plus we are adding 1
to both unit
and totalValue
. And is not like we are (a) creating only one unit. (b) adding only 1 to totalValue.
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 equation you wrote simplifies to totalUnits * addedValue = newUnits * totalValue
, which, solving for newUnits
, gives us totalUnits * addedValue / totalValue
, i.e. the equation in the code.
If we don't add 1 to those values no one can ever place a vote, since the numerator and denominator will both be zero
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.
Ok, thanks. I see the math now. The +1
were confusing.
I understand why you add them, but wouldn't be easier (and mathematically accurate) to first check if totalUnits == 0
; and if make delta = value
So that we end with:
totalUnits = value
totalValue = value
delta = value
userUnits = value
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 is much better, thanks!
* master: (37 commits) [Wallet] Add support for social wallet (Safeguards) import (#1414) [Wallet] Implement new backup flows including social backup (#1399) Use validator set precompiles in Attestations (#1248) E2E Attestations test + various e2e improvements (#1417) Update Footer (#1331) [Wallet] New camera permission flow (#1398) [Wallet] Enable push notifications on iOS (#1389) [Wallet] Add Celo Lite toggle (UI only, zeroSync on/off in other PR) (#1369) Document npm inter-repo dependencies instructions (#1370) [wallet]Add more documentation on ZeroSync mode (#1367) [wallet]Add documentation for jndcrash (#1364) Point end-to-end tests back to master (#1372) Alfajores changes & comment on unlocking accounts (#1297) Reconfigure terraform local configuration during init to allow multiple envs (#773) Implement proof-of-stake changes (#1177) [Celotool] Update blockchain-api deploy script to automatically update faucet address (#1347) Allow most recently reporting oracle to report again (#1288) [wallet]Add documentation for ZeroSync mode (#1361) Fix Metadata registration during contract deploy (#1346) [Wallet] Enable firebase on iOS (#1344) ...
* master: (128 commits) [Wallet] Add support for social wallet (Safeguards) import (#1414) [Wallet] Implement new backup flows including social backup (#1399) Use validator set precompiles in Attestations (#1248) E2E Attestations test + various e2e improvements (#1417) Update Footer (#1331) [Wallet] New camera permission flow (#1398) [Wallet] Enable push notifications on iOS (#1389) [Wallet] Add Celo Lite toggle (UI only, zeroSync on/off in other PR) (#1369) Document npm inter-repo dependencies instructions (#1370) [wallet]Add more documentation on ZeroSync mode (#1367) [wallet]Add documentation for jndcrash (#1364) Point end-to-end tests back to master (#1372) Alfajores changes & comment on unlocking accounts (#1297) Reconfigure terraform local configuration during init to allow multiple envs (#773) Implement proof-of-stake changes (#1177) [Celotool] Update blockchain-api deploy script to automatically update faucet address (#1347) Allow most recently reporting oracle to report again (#1288) [wallet]Add documentation for ZeroSync mode (#1361) Fix Metadata registration during contract deploy (#1346) [Wallet] Enable firebase on iOS (#1344) ...
* master: (37 commits) [Wallet] Add support for social wallet (Safeguards) import (#1414) [Wallet] Implement new backup flows including social backup (#1399) Use validator set precompiles in Attestations (#1248) E2E Attestations test + various e2e improvements (#1417) Update Footer (#1331) [Wallet] New camera permission flow (#1398) [Wallet] Enable push notifications on iOS (#1389) [Wallet] Add Celo Lite toggle (UI only, zeroSync on/off in other PR) (#1369) Document npm inter-repo dependencies instructions (#1370) [wallet]Add more documentation on ZeroSync mode (#1367) [wallet]Add documentation for jndcrash (#1364) Point end-to-end tests back to master (#1372) Alfajores changes & comment on unlocking accounts (#1297) Reconfigure terraform local configuration during init to allow multiple envs (#773) Implement proof-of-stake changes (#1177) [Celotool] Update blockchain-api deploy script to automatically update faucet address (#1347) Allow most recently reporting oracle to report again (#1288) [wallet]Add documentation for ZeroSync mode (#1361) Fix Metadata registration during contract deploy (#1346) [Wallet] Enable firebase on iOS (#1344) ...
Description
This PR implements changes to the proof of stake design.
Most notably, it:
Tested
Unit tests, manual tests of the CLI with ganache (with proof-of-possession disabled):
Other changes
Related issues
Backwards compatibility
Not backwards compatible