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 }