github.com/ava-labs/avalanchego@v1.11.11/vms/platformvm/state/stakers.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package state
     5  
     6  import (
     7  	"errors"
     8  
     9  	"github.com/google/btree"
    10  
    11  	"github.com/ava-labs/avalanchego/database"
    12  	"github.com/ava-labs/avalanchego/ids"
    13  	"github.com/ava-labs/avalanchego/utils/iterator"
    14  )
    15  
    16  var ErrAddingStakerAfterDeletion = errors.New("attempted to add a staker after deleting it")
    17  
    18  type Stakers interface {
    19  	CurrentStakers
    20  	PendingStakers
    21  }
    22  
    23  type CurrentStakers interface {
    24  	// GetCurrentValidator returns the [staker] describing the validator on
    25  	// [subnetID] with [nodeID]. If the validator does not exist,
    26  	// [database.ErrNotFound] is returned.
    27  	GetCurrentValidator(subnetID ids.ID, nodeID ids.NodeID) (*Staker, error)
    28  
    29  	// PutCurrentValidator adds the [staker] describing a validator to the
    30  	// staker set.
    31  	//
    32  	// Invariant: [staker] is not currently a CurrentValidator
    33  	PutCurrentValidator(staker *Staker) error
    34  
    35  	// DeleteCurrentValidator removes the [staker] describing a validator from
    36  	// the staker set.
    37  	//
    38  	// Invariant: [staker] is currently a CurrentValidator
    39  	DeleteCurrentValidator(staker *Staker)
    40  
    41  	// SetDelegateeReward sets the accrued delegation rewards for [nodeID] on
    42  	// [subnetID] to [amount].
    43  	SetDelegateeReward(subnetID ids.ID, nodeID ids.NodeID, amount uint64) error
    44  
    45  	// GetDelegateeReward returns the accrued delegation rewards for [nodeID] on
    46  	// [subnetID].
    47  	GetDelegateeReward(subnetID ids.ID, nodeID ids.NodeID) (uint64, error)
    48  
    49  	// GetCurrentDelegatorIterator returns the delegators associated with the
    50  	// validator on [subnetID] with [nodeID]. Delegators are sorted by their
    51  	// removal from current staker set.
    52  	GetCurrentDelegatorIterator(subnetID ids.ID, nodeID ids.NodeID) (iterator.Iterator[*Staker], error)
    53  
    54  	// PutCurrentDelegator adds the [staker] describing a delegator to the
    55  	// staker set.
    56  	//
    57  	// Invariant: [staker] is not currently a CurrentDelegator
    58  	PutCurrentDelegator(staker *Staker)
    59  
    60  	// DeleteCurrentDelegator removes the [staker] describing a delegator from
    61  	// the staker set.
    62  	//
    63  	// Invariant: [staker] is currently a CurrentDelegator
    64  	DeleteCurrentDelegator(staker *Staker)
    65  
    66  	// GetCurrentStakerIterator returns stakers in order of their removal from
    67  	// the current staker set.
    68  	GetCurrentStakerIterator() (iterator.Iterator[*Staker], error)
    69  }
    70  
    71  type PendingStakers interface {
    72  	// GetPendingValidator returns the Staker describing the validator on
    73  	// [subnetID] with [nodeID]. If the validator does not exist,
    74  	// [database.ErrNotFound] is returned.
    75  	GetPendingValidator(subnetID ids.ID, nodeID ids.NodeID) (*Staker, error)
    76  
    77  	// PutPendingValidator adds the [staker] describing a validator to the
    78  	// staker set.
    79  	PutPendingValidator(staker *Staker) error
    80  
    81  	// DeletePendingValidator removes the [staker] describing a validator from
    82  	// the staker set.
    83  	DeletePendingValidator(staker *Staker)
    84  
    85  	// GetPendingDelegatorIterator returns the delegators associated with the
    86  	// validator on [subnetID] with [nodeID]. Delegators are sorted by their
    87  	// removal from pending staker set.
    88  	GetPendingDelegatorIterator(subnetID ids.ID, nodeID ids.NodeID) (iterator.Iterator[*Staker], error)
    89  
    90  	// PutPendingDelegator adds the [staker] describing a delegator to the
    91  	// staker set.
    92  	PutPendingDelegator(staker *Staker)
    93  
    94  	// DeletePendingDelegator removes the [staker] describing a delegator from
    95  	// the staker set.
    96  	DeletePendingDelegator(staker *Staker)
    97  
    98  	// GetPendingStakerIterator returns stakers in order of their removal from
    99  	// the pending staker set.
   100  	GetPendingStakerIterator() (iterator.Iterator[*Staker], error)
   101  }
   102  
   103  type baseStakers struct {
   104  	// subnetID --> nodeID --> current state for the validator of the subnet
   105  	validators map[ids.ID]map[ids.NodeID]*baseStaker
   106  	stakers    *btree.BTreeG[*Staker]
   107  	// subnetID --> nodeID --> diff for that validator since the last db write
   108  	validatorDiffs map[ids.ID]map[ids.NodeID]*diffValidator
   109  }
   110  
   111  type baseStaker struct {
   112  	validator  *Staker
   113  	delegators *btree.BTreeG[*Staker]
   114  }
   115  
   116  func newBaseStakers() *baseStakers {
   117  	return &baseStakers{
   118  		validators:     make(map[ids.ID]map[ids.NodeID]*baseStaker),
   119  		stakers:        btree.NewG(defaultTreeDegree, (*Staker).Less),
   120  		validatorDiffs: make(map[ids.ID]map[ids.NodeID]*diffValidator),
   121  	}
   122  }
   123  
   124  func (v *baseStakers) GetValidator(subnetID ids.ID, nodeID ids.NodeID) (*Staker, error) {
   125  	subnetValidators, ok := v.validators[subnetID]
   126  	if !ok {
   127  		return nil, database.ErrNotFound
   128  	}
   129  	validator, ok := subnetValidators[nodeID]
   130  	if !ok {
   131  		return nil, database.ErrNotFound
   132  	}
   133  	if validator.validator == nil {
   134  		return nil, database.ErrNotFound
   135  	}
   136  	return validator.validator, nil
   137  }
   138  
   139  func (v *baseStakers) PutValidator(staker *Staker) {
   140  	validator := v.getOrCreateValidator(staker.SubnetID, staker.NodeID)
   141  	validator.validator = staker
   142  
   143  	validatorDiff := v.getOrCreateValidatorDiff(staker.SubnetID, staker.NodeID)
   144  	validatorDiff.validatorStatus = added
   145  	validatorDiff.validator = staker
   146  
   147  	v.stakers.ReplaceOrInsert(staker)
   148  }
   149  
   150  func (v *baseStakers) DeleteValidator(staker *Staker) {
   151  	validator := v.getOrCreateValidator(staker.SubnetID, staker.NodeID)
   152  	validator.validator = nil
   153  	v.pruneValidator(staker.SubnetID, staker.NodeID)
   154  
   155  	validatorDiff := v.getOrCreateValidatorDiff(staker.SubnetID, staker.NodeID)
   156  	validatorDiff.validatorStatus = deleted
   157  	validatorDiff.validator = staker
   158  
   159  	v.stakers.Delete(staker)
   160  }
   161  
   162  func (v *baseStakers) GetDelegatorIterator(subnetID ids.ID, nodeID ids.NodeID) iterator.Iterator[*Staker] {
   163  	subnetValidators, ok := v.validators[subnetID]
   164  	if !ok {
   165  		return iterator.Empty[*Staker]{}
   166  	}
   167  	validator, ok := subnetValidators[nodeID]
   168  	if !ok {
   169  		return iterator.Empty[*Staker]{}
   170  	}
   171  	return iterator.FromTree(validator.delegators)
   172  }
   173  
   174  func (v *baseStakers) PutDelegator(staker *Staker) {
   175  	validator := v.getOrCreateValidator(staker.SubnetID, staker.NodeID)
   176  	if validator.delegators == nil {
   177  		validator.delegators = btree.NewG(defaultTreeDegree, (*Staker).Less)
   178  	}
   179  	validator.delegators.ReplaceOrInsert(staker)
   180  
   181  	validatorDiff := v.getOrCreateValidatorDiff(staker.SubnetID, staker.NodeID)
   182  	if validatorDiff.addedDelegators == nil {
   183  		validatorDiff.addedDelegators = btree.NewG(defaultTreeDegree, (*Staker).Less)
   184  	}
   185  	validatorDiff.addedDelegators.ReplaceOrInsert(staker)
   186  
   187  	v.stakers.ReplaceOrInsert(staker)
   188  }
   189  
   190  func (v *baseStakers) DeleteDelegator(staker *Staker) {
   191  	validator := v.getOrCreateValidator(staker.SubnetID, staker.NodeID)
   192  	if validator.delegators != nil {
   193  		validator.delegators.Delete(staker)
   194  	}
   195  	v.pruneValidator(staker.SubnetID, staker.NodeID)
   196  
   197  	validatorDiff := v.getOrCreateValidatorDiff(staker.SubnetID, staker.NodeID)
   198  	if validatorDiff.deletedDelegators == nil {
   199  		validatorDiff.deletedDelegators = make(map[ids.ID]*Staker)
   200  	}
   201  	validatorDiff.deletedDelegators[staker.TxID] = staker
   202  
   203  	v.stakers.Delete(staker)
   204  }
   205  
   206  func (v *baseStakers) GetStakerIterator() iterator.Iterator[*Staker] {
   207  	return iterator.FromTree(v.stakers)
   208  }
   209  
   210  func (v *baseStakers) getOrCreateValidator(subnetID ids.ID, nodeID ids.NodeID) *baseStaker {
   211  	subnetValidators, ok := v.validators[subnetID]
   212  	if !ok {
   213  		subnetValidators = make(map[ids.NodeID]*baseStaker)
   214  		v.validators[subnetID] = subnetValidators
   215  	}
   216  	validator, ok := subnetValidators[nodeID]
   217  	if !ok {
   218  		validator = &baseStaker{}
   219  		subnetValidators[nodeID] = validator
   220  	}
   221  	return validator
   222  }
   223  
   224  // pruneValidator assumes that the named validator is currently in the
   225  // [validators] map.
   226  func (v *baseStakers) pruneValidator(subnetID ids.ID, nodeID ids.NodeID) {
   227  	subnetValidators := v.validators[subnetID]
   228  	validator := subnetValidators[nodeID]
   229  	if validator.validator != nil {
   230  		return
   231  	}
   232  	if validator.delegators != nil && validator.delegators.Len() > 0 {
   233  		return
   234  	}
   235  	delete(subnetValidators, nodeID)
   236  	if len(subnetValidators) == 0 {
   237  		delete(v.validators, subnetID)
   238  	}
   239  }
   240  
   241  func (v *baseStakers) getOrCreateValidatorDiff(subnetID ids.ID, nodeID ids.NodeID) *diffValidator {
   242  	subnetValidatorDiffs, ok := v.validatorDiffs[subnetID]
   243  	if !ok {
   244  		subnetValidatorDiffs = make(map[ids.NodeID]*diffValidator)
   245  		v.validatorDiffs[subnetID] = subnetValidatorDiffs
   246  	}
   247  	validatorDiff, ok := subnetValidatorDiffs[nodeID]
   248  	if !ok {
   249  		validatorDiff = &diffValidator{
   250  			validatorStatus: unmodified,
   251  		}
   252  		subnetValidatorDiffs[nodeID] = validatorDiff
   253  	}
   254  	return validatorDiff
   255  }
   256  
   257  type diffStakers struct {
   258  	// subnetID --> nodeID --> diff for that validator
   259  	validatorDiffs map[ids.ID]map[ids.NodeID]*diffValidator
   260  	addedStakers   *btree.BTreeG[*Staker]
   261  	deletedStakers map[ids.ID]*Staker
   262  }
   263  
   264  type diffValidator struct {
   265  	// validatorStatus describes whether a validator has been added or removed.
   266  	//
   267  	// validatorStatus is not affected by delegators ops so unmodified does not
   268  	// mean that diffValidator hasn't change, since delegators may have changed.
   269  	validatorStatus diffValidatorStatus
   270  	validator       *Staker
   271  
   272  	addedDelegators   *btree.BTreeG[*Staker]
   273  	deletedDelegators map[ids.ID]*Staker
   274  }
   275  
   276  // GetValidator attempts to fetch the validator with the given subnetID and
   277  // nodeID.
   278  // Invariant: Assumes that the validator will never be removed and then added.
   279  func (s *diffStakers) GetValidator(subnetID ids.ID, nodeID ids.NodeID) (*Staker, diffValidatorStatus) {
   280  	subnetValidatorDiffs, ok := s.validatorDiffs[subnetID]
   281  	if !ok {
   282  		return nil, unmodified
   283  	}
   284  
   285  	validatorDiff, ok := subnetValidatorDiffs[nodeID]
   286  	if !ok {
   287  		return nil, unmodified
   288  	}
   289  
   290  	if validatorDiff.validatorStatus == added {
   291  		return validatorDiff.validator, added
   292  	}
   293  	return nil, validatorDiff.validatorStatus
   294  }
   295  
   296  func (s *diffStakers) PutValidator(staker *Staker) error {
   297  	validatorDiff := s.getOrCreateDiff(staker.SubnetID, staker.NodeID)
   298  	if validatorDiff.validatorStatus == deleted {
   299  		// Enforce the invariant that a validator cannot be added after being
   300  		// deleted.
   301  		return ErrAddingStakerAfterDeletion
   302  	}
   303  
   304  	validatorDiff.validatorStatus = added
   305  	validatorDiff.validator = staker
   306  
   307  	if s.addedStakers == nil {
   308  		s.addedStakers = btree.NewG(defaultTreeDegree, (*Staker).Less)
   309  	}
   310  	s.addedStakers.ReplaceOrInsert(staker)
   311  	return nil
   312  }
   313  
   314  func (s *diffStakers) DeleteValidator(staker *Staker) {
   315  	validatorDiff := s.getOrCreateDiff(staker.SubnetID, staker.NodeID)
   316  	if validatorDiff.validatorStatus == added {
   317  		// This validator was added and immediately removed in this diff. We
   318  		// treat it as if it was never added.
   319  		validatorDiff.validatorStatus = unmodified
   320  		s.addedStakers.Delete(validatorDiff.validator)
   321  		validatorDiff.validator = nil
   322  	} else {
   323  		validatorDiff.validatorStatus = deleted
   324  		validatorDiff.validator = staker
   325  		if s.deletedStakers == nil {
   326  			s.deletedStakers = make(map[ids.ID]*Staker)
   327  		}
   328  		s.deletedStakers[staker.TxID] = staker
   329  	}
   330  }
   331  
   332  func (s *diffStakers) GetDelegatorIterator(
   333  	parentIterator iterator.Iterator[*Staker],
   334  	subnetID ids.ID,
   335  	nodeID ids.NodeID,
   336  ) iterator.Iterator[*Staker] {
   337  	var (
   338  		addedDelegatorIterator iterator.Iterator[*Staker] = iterator.Empty[*Staker]{}
   339  		deletedDelegators      map[ids.ID]*Staker
   340  	)
   341  	if subnetValidatorDiffs, ok := s.validatorDiffs[subnetID]; ok {
   342  		if validatorDiff, ok := subnetValidatorDiffs[nodeID]; ok {
   343  			addedDelegatorIterator = iterator.FromTree(validatorDiff.addedDelegators)
   344  			deletedDelegators = validatorDiff.deletedDelegators
   345  		}
   346  	}
   347  
   348  	return iterator.Filter(
   349  		iterator.Merge(
   350  			(*Staker).Less,
   351  			parentIterator,
   352  			addedDelegatorIterator,
   353  		),
   354  		func(staker *Staker) bool {
   355  			_, ok := deletedDelegators[staker.TxID]
   356  			return ok
   357  		},
   358  	)
   359  }
   360  
   361  func (s *diffStakers) PutDelegator(staker *Staker) {
   362  	validatorDiff := s.getOrCreateDiff(staker.SubnetID, staker.NodeID)
   363  	if validatorDiff.addedDelegators == nil {
   364  		validatorDiff.addedDelegators = btree.NewG(defaultTreeDegree, (*Staker).Less)
   365  	}
   366  	validatorDiff.addedDelegators.ReplaceOrInsert(staker)
   367  
   368  	if s.addedStakers == nil {
   369  		s.addedStakers = btree.NewG(defaultTreeDegree, (*Staker).Less)
   370  	}
   371  	s.addedStakers.ReplaceOrInsert(staker)
   372  }
   373  
   374  func (s *diffStakers) DeleteDelegator(staker *Staker) {
   375  	validatorDiff := s.getOrCreateDiff(staker.SubnetID, staker.NodeID)
   376  	if validatorDiff.deletedDelegators == nil {
   377  		validatorDiff.deletedDelegators = make(map[ids.ID]*Staker)
   378  	}
   379  	validatorDiff.deletedDelegators[staker.TxID] = staker
   380  
   381  	if s.deletedStakers == nil {
   382  		s.deletedStakers = make(map[ids.ID]*Staker)
   383  	}
   384  	s.deletedStakers[staker.TxID] = staker
   385  }
   386  
   387  func (s *diffStakers) GetStakerIterator(parentIterator iterator.Iterator[*Staker]) iterator.Iterator[*Staker] {
   388  	return iterator.Filter(
   389  		iterator.Merge(
   390  			(*Staker).Less,
   391  			parentIterator,
   392  			iterator.FromTree(s.addedStakers),
   393  		),
   394  		func(staker *Staker) bool {
   395  			_, ok := s.deletedStakers[staker.TxID]
   396  			return ok
   397  		},
   398  	)
   399  }
   400  
   401  func (s *diffStakers) getOrCreateDiff(subnetID ids.ID, nodeID ids.NodeID) *diffValidator {
   402  	if s.validatorDiffs == nil {
   403  		s.validatorDiffs = make(map[ids.ID]map[ids.NodeID]*diffValidator)
   404  	}
   405  	subnetValidatorDiffs, ok := s.validatorDiffs[subnetID]
   406  	if !ok {
   407  		subnetValidatorDiffs = make(map[ids.NodeID]*diffValidator)
   408  		s.validatorDiffs[subnetID] = subnetValidatorDiffs
   409  	}
   410  	validatorDiff, ok := subnetValidatorDiffs[nodeID]
   411  	if !ok {
   412  		validatorDiff = &diffValidator{
   413  			validatorStatus: unmodified,
   414  		}
   415  		subnetValidatorDiffs[nodeID] = validatorDiff
   416  	}
   417  	return validatorDiff
   418  }