Skip to content
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

feat: add /r/sys/validators #2130

Merged
merged 62 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
c4ef46b
Add the initial /sys/vals PoS implementation
zivkovicmilos May 16, 2024
8a6ea5c
Fix imports
zivkovicmilos May 17, 2024
e53e6bf
Add gno.mods, add initial PoA
zivkovicmilos May 17, 2024
9a8bc1d
Simplify API
zivkovicmilos May 17, 2024
b4a2452
Add initial PoS add validator tests
zivkovicmilos May 21, 2024
1c6a775
Add additional PoS tests
zivkovicmilos May 21, 2024
54884fd
Add initial PoS remove validator tests
zivkovicmilos May 21, 2024
afc2fcc
Merge branch 'master' into dev/zivkovicmilos/sys-vals
zivkovicmilos May 24, 2024
d2e1e24
Add unit tests for PoS validator removal
zivkovicmilos May 24, 2024
08f1351
Add unit tests for PoA validator operations
zivkovicmilos May 24, 2024
ee678fe
Cleanup
zivkovicmilos May 24, 2024
5a9385d
Merge branch 'master' into dev/zivkovicmilos/sys-vals
zivkovicmilos May 24, 2024
fe8ac45
Cleanup
zivkovicmilos May 24, 2024
4c21012
Fix stdshim std.Emit
zivkovicmilos May 24, 2024
6a76e48
Merge branch 'master' into dev/zivkovicmilos/sys-vals
zivkovicmilos Jun 3, 2024
997f6af
Apply suggestions for set scraping
zivkovicmilos Jun 3, 2024
2e5aca1
Merge master; adapt r/sys/vals
zivkovicmilos Jun 17, 2024
6e61bf8
Add PoC
zivkovicmilos Jun 17, 2024
28abe9b
Drop JSON output for valsets
zivkovicmilos Jun 17, 2024
26325c2
Cleanup
zivkovicmilos Jun 17, 2024
eb34c7a
Tidy gno mod
zivkovicmilos Jun 17, 2024
a3049c3
Move back to r/sys/vals
zivkovicmilos Jun 17, 2024
cfd900d
Tidy gno mod
zivkovicmilos Jun 17, 2024
f1151be
Tidy
zivkovicmilos Jun 18, 2024
32fc706
Tidy
zivkovicmilos Jun 18, 2024
2be7527
Move testing helpers to uassert
zivkovicmilos Jun 18, 2024
ce9329a
Add the 'testing' package to the whitelist
zivkovicmilos Jun 19, 2024
b388ef4
Merge branch 'master' into dev/zivkovicmilos/sys-vals
zivkovicmilos Jun 20, 2024
2c85e06
Revert "Move testing helpers to uassert"
zivkovicmilos Jun 20, 2024
40cf5bb
Tidy go mods
zivkovicmilos Jun 20, 2024
5562b5b
Merge branch 'master' into dev/zivkovicmilos/sys-vals
zivkovicmilos Jun 21, 2024
a28623f
Drop PoA / PoS in this scope
zivkovicmilos Jun 26, 2024
2d365dd
Temporary rename
zivkovicmilos Jun 26, 2024
d1e3c96
Temporary rename
zivkovicmilos Jun 26, 2024
32ec0b6
Switch to testutils
zivkovicmilos Jun 26, 2024
d213e89
Merge branch 'master' into dev/zivkovicmilos/sys-vals
zivkovicmilos Jun 26, 2024
d81d300
Add voting power to AddValidator API
zivkovicmilos Jun 26, 2024
68534e7
Add GetValidator to Protocol API
zivkovicmilos Jun 26, 2024
51414b0
Switch to avl.Tree for map in PoC
zivkovicmilos Jun 26, 2024
53de738
Rename Protocol -> ValsetProtocol
zivkovicmilos Jun 26, 2024
8b6130a
Temporary rename
zivkovicmilos Jun 26, 2024
0860453
Temporary rename
zivkovicmilos Jun 26, 2024
68a2723
Temporary rename
zivkovicmilos Jun 26, 2024
ed2f7a6
Update examples/gno.land/r/sys/vals/vals.gno
zivkovicmilos Jun 27, 2024
3a7fd9c
Simplify verify methods
zivkovicmilos Jun 27, 2024
751b5d3
Merge branch 'master' into dev/zivkovicmilos/sys-vals
zivkovicmilos Jun 28, 2024
6a5978f
Merge branch 'master' into dev/zivkovicmilos/sys-vals
zivkovicmilos Jun 28, 2024
b5e10f1
Use AVL to manage valsets
zivkovicmilos Jul 1, 2024
122e178
Simplify ValsetProtocol API
zivkovicmilos Jul 1, 2024
80fe0b4
Merge branch 'master' into dev/zivkovicmilos/sys-vals
zivkovicmilos Jul 1, 2024
5371852
Apply renames
zivkovicmilos Jul 1, 2024
e45814b
Tidy mods
zivkovicmilos Jul 1, 2024
96e1364
Rename vals -> validators
zivkovicmilos Jul 1, 2024
5e9c3e0
Update examples/gno.land/r/gnoland/home/home.gno
moul Jul 1, 2024
0f2fb39
Update examples/gno.land/r/gnoland/home/home_filetest.gno
moul Jul 1, 2024
da51c23
Update examples/gno.land/r/sys/validators/poc.gno
zivkovicmilos Jul 2, 2024
b25171d
Move getChanges to gnosdk.gno
zivkovicmilos Jul 2, 2024
fa341a6
Simplify valset to global package vars
zivkovicmilos Jul 2, 2024
a0fc2c1
Standardize return API for ValsetProtocol
zivkovicmilos Jul 2, 2024
55cdfb2
Merge branch 'master' into dev/zivkovicmilos/sys-vals
zivkovicmilos Jul 2, 2024
cc6bc62
Merge master
zivkovicmilos Jul 2, 2024
48d6471
Merge branch 'master' into dev/zivkovicmilos/sys-vals
zivkovicmilos Jul 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion examples/gno.land/r/sys/validators/gno.mod

This file was deleted.

4 changes: 0 additions & 4 deletions examples/gno.land/r/sys/validators/validators.gno
moul marked this conversation as resolved.
Show resolved Hide resolved

This file was deleted.

8 changes: 8 additions & 0 deletions examples/gno.land/r/sys/vals/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module gno.land/r/sys/vals

require (
gno.land/p/demo/json v0.0.0-latest
gno.land/p/demo/ufmt v0.0.0-latest
gno.land/r/sys/vals/poa v0.0.0-latest
gno.land/r/sys/vals/types v0.0.0-latest
)
6 changes: 6 additions & 0 deletions examples/gno.land/r/sys/vals/poa/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module gno.land/r/sys/vals/poa

require (
gno.land/p/demo/ufmt v0.0.0-latest
gno.land/r/sys/vals/types v0.0.0-latest
)
19 changes: 19 additions & 0 deletions examples/gno.land/r/sys/vals/poa/option.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package poa

import "gno.land/r/sys/vals/types"

type Option func(*PoA)

// WithInitialSet sets the initial PoA validator set
func WithInitialSet(validators []*types.Validator) Option {
return func(p *PoA) {
for index, validator := range validators {
p.validators = append(p.validators, validator)
p.addressToValidatorIndex[validator.Address] = index

p.totalVotingPower += validator.VotingPower
}

p.majorityPower = (2 * p.totalVotingPower) / 3
}
}
220 changes: 220 additions & 0 deletions examples/gno.land/r/sys/vals/poa/poa.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
package poa

import (
"std"

"gno.land/r/sys/vals/types"
)

const (
UserVotedAddEvent = "UserVotedAdd" // emitted when someone votes to add a validator
UserVotedRemoveEvent = "UserVotedRemove" // emitted when someone votes to remove a validator
)

var errCallerNotValidator = "caller is not validator"

// PoA specifies the Proof of Authority validator set.
// In order to become part of the set, users to be voted into
// the validator set by the majority of the existing set
type PoA struct {
// validators holds the current validator set.
// This slice can never practically grow more than ~150 elements,
// due to Tendermint's quadratic network complexity
validators []*types.Validator
addressToValidatorIndex map[std.Address]int // address -> index
votes *votingSystem // system that keeps track of votes

totalVotingPower uint64 // cached value for quick lookups
majorityPower uint64 // cached value for quick lookups
}

// NewPoA creates a new empty Proof of Authority validator set
func NewPoA(opts ...Option) *PoA {
// Create the empty set
p := &PoA{
validators: make([]*types.Validator, 0),
addressToValidatorIndex: make(map[std.Address]int),
votes: newVotingSystem(),
}

// Apply the options
for _, opt := range opts {
opt(p)
}

return p
}

// AddValidator adds a vote to add a new validator to the validator set.
//
// Criteria for being added:
// - caller is a user account
// - caller is a validator
// - the proposed address is not a validator
// - a 2/3+ majority of the set have voted to add
func (p *PoA) AddValidator(address std.Address, pubKey string) {
caller := std.GetOrigCaller()

// Validate that the operation is a valid call
p.validateAdd(caller, address)

// Cast the vote
p.votes.castVote(caller, address, true)

// Emit the vote event
std.Emit(
UserVotedAddEvent,
"address", address.String(),
"voter", caller.String(),
)

// Calculate the votes
addCount, _ := p.votes.getTally(address)

// Check if there is a majority
// to apply the action
if addCount <= p.majorityPower {
// No super majority to add
return
}

// Execute the decision
v := &types.Validator{
Address: address,
PubKey: pubKey, // TODO: in the future, verify the public key
VotingPower: 1, // in this PoA system, all new validators have the same voting power
}

p.addValidator(v)
}

// validateAdd validates a validator add call
func (p *PoA) validateAdd(caller, address std.Address) {
// Check if the caller is a user account
if !std.PrevRealm().IsUser() {
panic(types.ErrCallerNotUserAccount)
}

// Check if the caller is in the set
if !p.IsValidator(caller) {
panic(types.ErrValidatorMissing)
}

// Check if the validator is already in the set
if p.IsValidator(address) {
panic(types.ErrValidatorExists)
}
}

// addValidator adds the given validator to the PoA validator set
func (p *PoA) addValidator(v *types.Validator) {
// Add the validator to the set
p.addressToValidatorIndex[v.Address] = len(p.validators)
p.validators = append(p.validators, v)

// Update the total voting power
p.totalVotingPower += v.VotingPower
p.majorityPower = (2 * p.totalVotingPower) / 3

// Emit the validator set change
std.Emit(
types.ValidatorAddedEvent,
"address", v.Address.String(),
)

// Remove the candidate from the voting system
p.votes.resetCandidate(v.Address)
}

// RemoveValidator adds a vote to remove a validator from the validator set.
//
// Criteria for being added:
// - caller is a user account
// - caller is a validator
// - the proposed address is a validator
// - a 2/3+ majority of the set have voted to remove
func (p *PoA) RemoveValidator(address std.Address) {
caller := std.GetOrigCaller()

// Validate that the operation is a valid call
p.validateRemove(caller, address)

// Cast the vote
p.votes.castVote(caller, address, false)

// Emit the vote event
std.Emit(
UserVotedRemoveEvent,
"address", address.String(),
"voter", caller.String(),
)

// Calculate the votes
_, removeCount := p.votes.getTally(address)

// Check if there is a majority
// to apply the action
if removeCount <= p.majorityPower {
// No super majority to remove
return
}

// Execute the decision
p.removeValidator(address)
}

// validateRemove validates a validator remove call
func (p *PoA) validateRemove(caller, address std.Address) {
// Check if the caller is a user account
if !std.PrevRealm().IsUser() {
panic(types.ErrCallerNotUserAccount)
}

// Check if this request came from a validator
if !p.IsValidator(caller) {
panic(errCallerNotValidator)
}

// Check if the address is a validator
if !p.IsValidator(address) {
panic(types.ErrValidatorMissing)
}
}

// removeValidator removes the given address from the PoA validator set
func (p *PoA) removeValidator(address std.Address) {
// Fetch the validator index
index := p.addressToValidatorIndex[address]

// Remove the validator from the set
validator := p.validators[index]
p.validators = append(p.validators[:index], p.validators[index+1:]...)

delete(p.addressToValidatorIndex, address)

// Update the total voting power
p.totalVotingPower -= validator.VotingPower
p.majorityPower = (2 * p.totalVotingPower) / 3

// Emit the validator set change
std.Emit(
types.ValidatorRemovedEvent,
"address", address.String(),
)

// Remove the candidate from the voting system
p.votes.resetCandidate(address)
}

// IsValidator returns a flag indicating if the address
// is part of the staked validator set
func (p *PoA) IsValidator(address std.Address) bool {
_, exists := p.addressToValidatorIndex[address]

return exists
}

// GetValidators returns the current staked validator set
func (p *PoA) GetValidators() []*types.Validator {
return p.validators
}
Loading
Loading