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

move interfaces to separate pkgs #1379

Merged
merged 41 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
ce36343
add validator state
ceyonur Sep 16, 2024
549d319
add pausable uptime manager
ceyonur Sep 16, 2024
9987248
remove stuttering name
ceyonur Sep 16, 2024
e1ef744
Merge branch 'master' into validator-state
ceyonur Sep 16, 2024
b33ffbe
Merge branch 'validator-state' into pausable-uptime-manager
ceyonur Sep 16, 2024
0f16af2
rename state listener
ceyonur Sep 16, 2024
df3ce63
Merge branch 'validator-state' into pausable-uptime-manager
ceyonur Sep 16, 2024
92f6b7e
Update plugin/evm/validators/state.go
ceyonur Sep 19, 2024
0db2041
use update enum
ceyonur Sep 19, 2024
c5520bc
Update plugin/evm/validators/state.go
ceyonur Sep 19, 2024
dea94af
Update plugin/evm/validators/state.go
ceyonur Sep 19, 2024
c0f6ff4
respond to comments
ceyonur Sep 19, 2024
b7de0f6
Merge branch 'validator-state' of https://github.com/ava-labs/subnet-…
ceyonur Sep 19, 2024
b566103
update avalanchego dep branch
ceyonur Sep 19, 2024
66ab74b
update avalanchego dep branch
ceyonur Sep 19, 2024
ad3a35a
reviews
ceyonur Sep 19, 2024
64fe238
reword errs
ceyonur Sep 19, 2024
33d24d1
Merge branch 'pausable-uptime-manager' of https://github.com/ava-labs…
ceyonur Sep 19, 2024
d7338da
fix test changes
ceyonur Sep 19, 2024
8eab611
Merge branch 'master' into uptime-tracking-base
ceyonur Sep 19, 2024
9ad5528
fix upgrades after deactivating latest in context
ceyonur Sep 19, 2024
4536590
Merge branch 'uptime-tracking-base' into validator-state
ceyonur Sep 19, 2024
fc71949
Merge branch 'validator-state' into pausable-uptime-manager
ceyonur Sep 19, 2024
df6ad02
use branch commit for ava version
ceyonur Sep 20, 2024
cc6ce95
Merge branch 'master' into uptime-tracking-base
ceyonur Sep 20, 2024
bcd4c9c
Merge branch 'uptime-tracking-base' into validator-state
ceyonur Sep 20, 2024
a49dd8d
Merge branch 'validator-state' into pausable-uptime-manager
ceyonur Sep 20, 2024
734b201
Merge branch 'master' into validator-state
ceyonur Oct 28, 2024
3e94861
Merge branch 'validator-state' into pausable-uptime-manager
ceyonur Oct 28, 2024
cab1ddf
reviews
ceyonur Oct 29, 2024
374d885
add listener mock
ceyonur Oct 29, 2024
1fcca58
Merge branch 'master' into validator-state
ceyonur Oct 29, 2024
c41f39c
Merge branch 'validator-state' into pausable-uptime-manager
ceyonur Oct 29, 2024
af39b2c
remove errs from resume and pause
ceyonur Oct 30, 2024
d5d3545
check after stopping
ceyonur Oct 30, 2024
6fffc2b
use expectedTime in tests
ceyonur Oct 31, 2024
733da4c
Merge branch 'master' into pausable-uptime-manager
ceyonur Nov 5, 2024
66fa2aa
reviews
ceyonur Nov 5, 2024
1e98831
move interfaces to separate pkgs
ceyonur Nov 5, 2024
ad44a00
regen mock
ceyonur Nov 5, 2024
e987b9b
Merge branch 'master' into uptime-interfaces-pkgs
ceyonur Nov 5, 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
126 changes: 63 additions & 63 deletions plugin/evm/validators/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ import (

var _ uptime.State = &state{}

type ValidatorState interface {
type State interface {
uptime.State
// AddNewValidator adds a new validator to the state
AddNewValidator(vID ids.ID, nodeID ids.NodeID, startTimestamp uint64, isActive bool) error
// DeleteValidator deletes the validator from the state
DeleteValidator(vID ids.ID) error
// WriteValidatorState writes the validator state to the disk
WriteValidatorState() error
// WriteState writes the validator state to the disk
WriteState() error

// SetStatus sets the active status of the validator with the given vID
SetStatus(vID ids.ID, isActive bool) error
Expand All @@ -35,11 +35,11 @@ type ValidatorState interface {
GetValidatorIDs() set.Set[ids.NodeID]

// RegisterListener registers a listener to the state
RegisterListener(ValidatorsCallbackListener)
RegisterListener(StateCallbackListener)
}

// ValidatorsCallbackListener is a listener for the validator state
type ValidatorsCallbackListener interface {
// StateCallbackListener is a listener for the validator state
type StateCallbackListener interface {
// OnValidatorAdded is called when a new validator is added
OnValidatorAdded(vID ids.ID, nodeID ids.NodeID, startTime uint64, isActive bool)
// OnValidatorRemoved is called when a validator is removed
Expand Down Expand Up @@ -67,63 +67,63 @@ type state struct {
updatedData map[ids.ID]bool // vID -> true(updated)/false(deleted)
db database.Database

listeners []ValidatorsCallbackListener
listeners []StateCallbackListener
}

// NewValidatorState creates a new ValidatorState, it also loads the data from the disk
func NewValidatorState(db database.Database) (ValidatorState, error) {
m := &state{
// NewState creates a new State, it also loads the data from the disk
func NewState(db database.Database) (State, error) {
s := &state{
index: make(map[ids.NodeID]ids.ID),
data: make(map[ids.ID]*validatorData),
updatedData: make(map[ids.ID]bool),
db: db,
}
if err := m.loadFromDisk(); err != nil {
if err := s.loadFromDisk(); err != nil {
return nil, fmt.Errorf("failed to load data from disk: %w", err)
}
return m, nil
return s, nil
}

// GetUptime returns the uptime of the validator with the given nodeID
func (m *state) GetUptime(
func (s *state) GetUptime(
nodeID ids.NodeID,
) (time.Duration, time.Time, error) {
data, err := m.getData(nodeID)
data, err := s.getData(nodeID)
if err != nil {
return 0, time.Time{}, err
}
return data.UpDuration, data.lastUpdated, nil
}

// SetUptime sets the uptime of the validator with the given nodeID
func (m *state) SetUptime(
func (s *state) SetUptime(
nodeID ids.NodeID,
upDuration time.Duration,
lastUpdated time.Time,
) error {
data, err := m.getData(nodeID)
data, err := s.getData(nodeID)
if err != nil {
return err
}
data.UpDuration = upDuration
data.lastUpdated = lastUpdated

m.updatedData[data.validationID] = true
s.updatedData[data.validationID] = true
return nil
}

// GetStartTime returns the start time of the validator with the given nodeID
func (m *state) GetStartTime(nodeID ids.NodeID) (time.Time, error) {
data, err := m.getData(nodeID)
func (s *state) GetStartTime(nodeID ids.NodeID) (time.Time, error) {
data, err := s.getData(nodeID)
if err != nil {
return time.Time{}, err
}
return data.startTime, nil
}

// AddNewValidator adds a new validator to the state
// the new validator is marked as updated and will be written to the disk when WriteValidatorState is called
func (m *state) AddNewValidator(vID ids.ID, nodeID ids.NodeID, startTimestamp uint64, isActive bool) error {
// the new validator is marked as updated and will be written to the disk when WriteState is called
func (s *state) AddNewValidator(vID ids.ID, nodeID ids.NodeID, startTimestamp uint64, isActive bool) error {
startTimeUnix := time.Unix(int64(startTimestamp), 0)

data := &validatorData{
Expand All @@ -136,44 +136,44 @@ func (m *state) AddNewValidator(vID ids.ID, nodeID ids.NodeID, startTimestamp ui
lastUpdated: startTimeUnix,
startTime: startTimeUnix,
}
if err := m.putData(vID, data); err != nil {
if err := s.putData(vID, data); err != nil {
return err
}

m.updatedData[vID] = true
s.updatedData[vID] = true

for _, listener := range m.listeners {
for _, listener := range s.listeners {
listener.OnValidatorAdded(vID, nodeID, startTimestamp, isActive)
}
return nil
}

// DeleteValidator marks the validator as deleted
// marked validator will be deleted from disk when WriteValidatorState is called
func (m *state) DeleteValidator(vID ids.ID) error {
data, exists := m.data[vID]
// marked validator will be deleted from disk when WriteState is called
func (s *state) DeleteValidator(vID ids.ID) error {
data, exists := s.data[vID]
if !exists {
return database.ErrNotFound
}
delete(m.data, data.validationID)
delete(m.index, data.NodeID)
delete(s.data, data.validationID)
delete(s.index, data.NodeID)

// mark as deleted for WriteValidator
m.updatedData[data.validationID] = false
s.updatedData[data.validationID] = false

for _, listener := range m.listeners {
for _, listener := range s.listeners {
listener.OnValidatorRemoved(vID, data.NodeID)
}
return nil
}

// WriteValidatorState writes the updated state to the disk
func (m *state) WriteValidatorState() error {
// WriteState writes the updated state to the disk
func (s *state) WriteState() error {
// TODO: consider adding batch size
batch := m.db.NewBatch()
for vID, updated := range m.updatedData {
batch := s.db.NewBatch()
for vID, updated := range s.updatedData {
if updated {
data := m.data[vID]
data := s.data[vID]
data.LastUpdated = uint64(data.lastUpdated.Unix())
// should never change but in case
data.StartTime = uint64(data.startTime.Unix())
Expand All @@ -191,60 +191,60 @@ func (m *state) WriteValidatorState() error {
}
}
// we're done, remove the updated marker
delete(m.updatedData, vID)
delete(s.updatedData, vID)
}
return batch.Write()
}

// SetStatus sets the active status of the validator with the given vID
func (m *state) SetStatus(vID ids.ID, isActive bool) error {
data, exists := m.data[vID]
func (s *state) SetStatus(vID ids.ID, isActive bool) error {
data, exists := s.data[vID]
if !exists {
return database.ErrNotFound
}
data.IsActive = isActive
m.updatedData[vID] = true
s.updatedData[vID] = true

for _, listener := range m.listeners {
for _, listener := range s.listeners {
listener.OnValidatorStatusUpdated(vID, data.NodeID, isActive)
}
return nil
}

// GetStatus returns the active status of the validator with the given vID
func (m *state) GetStatus(vID ids.ID) (bool, error) {
data, exists := m.data[vID]
func (s *state) GetStatus(vID ids.ID) (bool, error) {
data, exists := s.data[vID]
if !exists {
return false, database.ErrNotFound
}
return data.IsActive, nil
}

// GetValidationIDs returns the validation IDs in the state
func (m *state) GetValidationIDs() set.Set[ids.ID] {
ids := set.NewSet[ids.ID](len(m.data))
for vID := range m.data {
func (s *state) GetValidationIDs() set.Set[ids.ID] {
ids := set.NewSet[ids.ID](len(s.data))
for vID := range s.data {
ids.Add(vID)
}
return ids
}

// GetValidatorIDs returns the validator IDs in the state
func (m *state) GetValidatorIDs() set.Set[ids.NodeID] {
ids := set.NewSet[ids.NodeID](len(m.index))
for nodeID := range m.index {
func (s *state) GetValidatorIDs() set.Set[ids.NodeID] {
ids := set.NewSet[ids.NodeID](len(s.index))
for nodeID := range s.index {
ids.Add(nodeID)
}
return ids
}

// RegisterListener registers a listener to the state
// the listener will be notified of current validators via OnValidatorAdded
func (m *state) RegisterListener(listener ValidatorsCallbackListener) {
m.listeners = append(m.listeners, listener)
func (s *state) RegisterListener(listener StateCallbackListener) {
s.listeners = append(s.listeners, listener)

// notify the listener of the current state
for vID, data := range m.data {
for vID, data := range s.data {
listener.OnValidatorAdded(vID, data.NodeID, uint64(data.startTime.Unix()), data.IsActive)
}
}
Expand All @@ -262,8 +262,8 @@ func parseValidatorData(bytes []byte, data *validatorData) error {
}

// Load the state from the disk
func (m *state) loadFromDisk() error {
it := m.db.NewIterator()
func (s *state) loadFromDisk() error {
it := s.db.NewIterator()
defer it.Release()
for it.Next() {
vIDBytes := it.Key()
Expand All @@ -277,35 +277,35 @@ func (m *state) loadFromDisk() error {
if err := parseValidatorData(it.Value(), vdr); err != nil {
return fmt.Errorf("failed to parse validator data: %w", err)
}
if err := m.putData(vID, vdr); err != nil {
if err := s.putData(vID, vdr); err != nil {
return err
}
}
return it.Error()
}

func (m *state) putData(vID ids.ID, data *validatorData) error {
if _, exists := m.data[vID]; exists {
func (s *state) putData(vID ids.ID, data *validatorData) error {
if _, exists := s.data[vID]; exists {
return fmt.Errorf("validator data already exists for %s", vID)
}
// should never happen
if _, exists := m.index[data.NodeID]; exists {
if _, exists := s.index[data.NodeID]; exists {
return fmt.Errorf("validator data already exists for %s", data.NodeID)
}

m.data[vID] = data
m.index[data.NodeID] = vID
s.data[vID] = data
s.index[data.NodeID] = vID
return nil
}

// getData returns the data for the validator with the given nodeID
// returns ErrNotFound if the data does not exist
func (m *state) getData(nodeID ids.NodeID) (*validatorData, error) {
vID, exists := m.index[nodeID]
func (s *state) getData(nodeID ids.NodeID) (*validatorData, error) {
vID, exists := s.index[nodeID]
if !exists {
return nil, database.ErrNotFound
}
data, exists := m.data[vID]
data, exists := s.data[vID]
if !exists {
return nil, database.ErrNotFound
}
Expand Down
20 changes: 10 additions & 10 deletions plugin/evm/validators/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ import (
"github.com/ava-labs/avalanchego/utils/wrappers"
)

func TestValidatorState(t *testing.T) {
func TestState(t *testing.T) {
require := require.New(t)
db := memdb.New()
state, err := NewValidatorState(db)
state, err := NewState(db)
require.NoError(err)

// get non-existent uptime
Expand Down Expand Up @@ -77,10 +77,10 @@ func TestValidatorState(t *testing.T) {
func TestWriteValidator(t *testing.T) {
require := require.New(t)
db := memdb.New()
state, err := NewValidatorState(db)
state, err := NewState(db)
require.NoError(err)
// write empty uptimes
require.NoError(state.WriteValidatorState())
require.NoError(state.WriteState())

// load uptime
nodeID := ids.GenerateTestNodeID()
Expand All @@ -89,17 +89,17 @@ func TestWriteValidator(t *testing.T) {
state.AddNewValidator(vID, nodeID, uint64(startTime.Unix()), true)

// write state, should reflect to DB
require.NoError(state.WriteValidatorState())
require.NoError(state.WriteState())
require.True(db.Has(vID[:]))

// set uptime
newUpDuration := 2 * time.Minute
newLastUpdated := startTime.Add(time.Hour)
require.NoError(state.SetUptime(nodeID, newUpDuration, newLastUpdated))
require.NoError(state.WriteValidatorState())
require.NoError(state.WriteState())

// refresh state, should load from DB
state, err = NewValidatorState(db)
state, err = NewState(db)
require.NoError(err)

// get uptime
Expand All @@ -112,7 +112,7 @@ func TestWriteValidator(t *testing.T) {
state.DeleteValidator(vID)

// write state, should reflect to DB
require.NoError(state.WriteValidatorState())
require.NoError(state.WriteState())
require.False(db.Has(vID[:]))
}

Expand Down Expand Up @@ -216,7 +216,7 @@ func TestParseValidator(t *testing.T) {
func TestStateListener(t *testing.T) {
require := require.New(t)
db := memdb.New()
state, err := NewValidatorState(db)
state, err := NewState(db)
require.NoError(err)

expectedvID := ids.GenerateTestID()
Expand Down Expand Up @@ -254,7 +254,7 @@ func TestStateListener(t *testing.T) {
state.DeleteValidator(expectedvID)
}

var _ ValidatorsCallbackListener = (*testCallbackListener)(nil)
var _ StateCallbackListener = (*testCallbackListener)(nil)

type testCallbackListener struct {
t *testing.T
Expand Down