github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/staking/candidate_center.go (about) 1 // Copyright (c) 2020 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package staking 7 8 import ( 9 "sync" 10 11 "github.com/iotexproject/iotex-address/address" 12 13 "github.com/iotexproject/iotex-core/action" 14 "github.com/iotexproject/iotex-core/action/protocol" 15 ) 16 17 type ( 18 // candChange captures the change to candidates 19 candChange struct { 20 candidates []*Candidate 21 dirty map[string]*Candidate 22 } 23 24 // candBase is the confirmed base state 25 candBase struct { 26 lock sync.RWMutex 27 nameMap map[string]*Candidate 28 ownerMap map[string]*Candidate 29 operatorMap map[string]*Candidate 30 selfStkBucketMap map[uint64]*Candidate 31 owners CandidateList 32 } 33 34 // CandidateCenter is a struct to manage the candidates 35 CandidateCenter struct { 36 base *candBase 37 size int 38 change *candChange 39 } 40 ) 41 42 // listToCandChange creates a candChange from list 43 func listToCandChange(l CandidateList) (*candChange, error) { 44 cv := newCandChange() 45 46 for _, d := range l { 47 if err := d.Validate(); err != nil { 48 return nil, err 49 } 50 cv.candidates = append(cv.candidates, d) 51 cv.dirty[d.Owner.String()] = d 52 } 53 return cv, nil 54 } 55 56 // NewCandidateCenter creates an instance of CandidateCenter 57 func NewCandidateCenter(all CandidateList) (*CandidateCenter, error) { 58 delta, err := listToCandChange(all) 59 if err != nil { 60 return nil, err 61 } 62 63 c := CandidateCenter{ 64 base: newCandBase(), 65 change: delta, 66 } 67 68 if len(all) == 0 { 69 return &c, nil 70 } 71 72 if err := c.Commit(); err != nil { 73 return nil, err 74 } 75 return &c, nil 76 } 77 78 // Size returns number of candidates 79 func (m *CandidateCenter) Size() int { 80 return m.size 81 } 82 83 // All returns all candidates in candidate center 84 func (m *CandidateCenter) All() CandidateList { 85 list := m.change.view() 86 if list == nil { 87 return m.base.all() 88 } 89 90 for _, d := range m.base.all() { 91 if !m.change.containsOwner(d.Owner) { 92 list = append(list, d.Clone()) 93 } 94 } 95 return list 96 } 97 98 // Base returns the confirmed base state 99 func (m CandidateCenter) Base() *CandidateCenter { 100 return &CandidateCenter{ 101 base: m.base, 102 size: len(m.base.ownerMap), 103 change: newCandChange(), 104 } 105 } 106 107 // Delta exports the pending changes 108 func (m *CandidateCenter) Delta() CandidateList { 109 return m.change.items() 110 } 111 112 // SetDelta sets the delta 113 func (m *CandidateCenter) SetDelta(l CandidateList) error { 114 if len(l) == 0 { 115 m.change = nil 116 m.change = newCandChange() 117 m.size = m.base.size() 118 return nil 119 } 120 121 var err error 122 m.change, err = listToCandChange(l) 123 if err != nil { 124 return err 125 } 126 if m.base.size() == 0 { 127 m.size = m.change.size() 128 return nil 129 } 130 131 overlap := 0 132 for _, v := range m.base.all() { 133 if m.change.containsOwner(v.Owner) { 134 overlap++ 135 } 136 } 137 m.size = m.base.size() + m.change.size() - overlap 138 return nil 139 } 140 141 // Commit writes the change into base 142 func (m *CandidateCenter) Commit() error { 143 size, err := m.base.commit(m.change, false) 144 if err != nil { 145 return err 146 } 147 m.size = size 148 m.change = nil 149 m.change = newCandChange() 150 return nil 151 } 152 153 // LegacyCommit writes the change into base with legacy logic 154 func (m *CandidateCenter) LegacyCommit() error { 155 size, err := m.base.commit(m.change, true) 156 if err != nil { 157 return err 158 } 159 m.size = size 160 m.change = nil 161 m.change = newCandChange() 162 return nil 163 } 164 165 // Sync syncs the data from state manager 166 func (m *CandidateCenter) Sync(sm protocol.StateManager) error { 167 delta := CandidateList{} 168 if err := sm.Unload(_protocolID, _stakingCandCenter, &delta); err != nil && err != protocol.ErrNoName { 169 return err 170 } 171 172 // apply delta to the center 173 return m.SetDelta(delta) 174 } 175 176 // ContainsName returns true if the map contains the candidate by name 177 func (m *CandidateCenter) ContainsName(name string) bool { 178 if hit := m.change.containsName(name); hit { 179 return true 180 } 181 182 if d, hit := m.base.getByName(name); hit { 183 return !m.change.containsOwner(d.Owner) 184 } 185 return false 186 } 187 188 // ContainsOwner returns true if the map contains the candidate by owner 189 func (m *CandidateCenter) ContainsOwner(owner address.Address) bool { 190 if owner == nil { 191 return false 192 } 193 194 if hit := m.change.containsOwner(owner); hit { 195 return true 196 } 197 198 _, hit := m.base.getByOwner(owner.String()) 199 return hit 200 } 201 202 // ContainsOperator returns true if the map contains the candidate by operator 203 func (m *CandidateCenter) ContainsOperator(operator address.Address) bool { 204 if operator == nil { 205 return false 206 } 207 208 if hit := m.change.containsOperator(operator); hit { 209 return true 210 } 211 212 if d, hit := m.base.getByOperator(operator.String()); hit { 213 return !m.change.containsOwner(d.Owner) 214 } 215 return false 216 } 217 218 // ContainsSelfStakingBucket returns true if the map contains the self staking bucket index 219 func (m *CandidateCenter) ContainsSelfStakingBucket(index uint64) bool { 220 if hit := m.change.containsSelfStakingBucket(index); hit { 221 return true 222 } 223 224 if d, hit := m.base.getBySelfStakingIndex(index); hit { 225 return !m.change.containsOwner(d.Owner) 226 } 227 return false 228 } 229 230 // GetByName returns the candidate by name 231 func (m *CandidateCenter) GetByName(name string) *Candidate { 232 if d := m.change.getByName(name); d != nil { 233 return d 234 } 235 236 if d, hit := m.base.getByName(name); hit && !m.change.containsOwner(d.Owner) { 237 return d.Clone() 238 } 239 return nil 240 } 241 242 // GetByOwner returns the candidate by owner 243 func (m *CandidateCenter) GetByOwner(owner address.Address) *Candidate { 244 if owner == nil { 245 return nil 246 } 247 248 if d := m.change.getByOwner(owner); d != nil { 249 return d 250 } 251 252 if d, hit := m.base.getByOwner(owner.String()); hit { 253 return d.Clone() 254 } 255 return nil 256 } 257 258 // GetBySelfStakingIndex returns the candidate by self-staking index 259 func (m *CandidateCenter) GetBySelfStakingIndex(index uint64) *Candidate { 260 if d := m.change.getBySelfStakingIndex(index); d != nil { 261 return d 262 } 263 264 if d, hit := m.base.getBySelfStakingIndex(index); hit && !m.change.containsOwner(d.Owner) { 265 return d.Clone() 266 } 267 return nil 268 } 269 270 // Upsert adds a candidate into map, overwrites if already exist 271 func (m *CandidateCenter) Upsert(d *Candidate) error { 272 if err := d.Validate(); err != nil { 273 return err 274 } 275 276 if err := m.collision(d); err != nil { 277 return err 278 } 279 280 if err := m.change.upsert(d); err != nil { 281 return err 282 } 283 284 if _, hit := m.base.getByOwner(d.Owner.String()); !hit { 285 m.size++ 286 } 287 return nil 288 } 289 290 func (m *CandidateCenter) collision(d *Candidate) error { 291 if err := m.change.collision(d); err != nil { 292 return err 293 } 294 295 name, oper, self := m.base.collision(d) 296 if name != nil && !m.change.containsOwner(name) { 297 return action.ErrInvalidCanName 298 } 299 300 if oper != nil && !m.change.containsOwner(oper) { 301 return ErrInvalidOperator 302 } 303 304 if self != nil && !m.change.containsOwner(self) { 305 return ErrInvalidSelfStkIndex 306 } 307 return nil 308 } 309 310 //====================================== 311 // candChange funcs 312 //====================================== 313 314 func newCandChange() *candChange { 315 return &candChange{ 316 dirty: make(map[string]*Candidate), 317 } 318 } 319 320 func (cc *candChange) size() int { 321 return len(cc.dirty) 322 } 323 324 func (cc *candChange) view() CandidateList { 325 if len(cc.dirty) == 0 { 326 return nil 327 } 328 329 list := make(CandidateList, 0, len(cc.dirty)) 330 for _, d := range cc.dirty { 331 list = append(list, d.Clone()) 332 } 333 return list 334 } 335 336 func (cc *candChange) items() CandidateList { 337 var retval CandidateList 338 for _, c := range cc.candidates { 339 retval = append(retval, c.Clone()) 340 } 341 return retval 342 } 343 344 func (cc *candChange) containsName(name string) bool { 345 for _, d := range cc.dirty { 346 if name == d.Name { 347 return true 348 } 349 } 350 return false 351 } 352 353 func (cc *candChange) containsOwner(owner address.Address) bool { 354 if owner == nil { 355 return false 356 } 357 _, ok := cc.dirty[owner.String()] 358 return ok 359 } 360 361 func (cc *candChange) containsOperator(operator address.Address) bool { 362 for _, d := range cc.dirty { 363 if address.Equal(operator, d.Operator) { 364 return true 365 } 366 } 367 return false 368 } 369 370 func (cc *candChange) containsSelfStakingBucket(index uint64) bool { 371 for _, d := range cc.dirty { 372 if d.isSelfStakeBucketSettled() && index == d.SelfStakeBucketIdx { 373 return true 374 } 375 } 376 return false 377 } 378 379 func (cc *candChange) getByName(name string) *Candidate { 380 for _, d := range cc.dirty { 381 if name == d.Name { 382 return d.Clone() 383 } 384 } 385 return nil 386 } 387 388 func (cc *candChange) getByOwner(owner address.Address) *Candidate { 389 if owner == nil { 390 return nil 391 } 392 393 if d, ok := cc.dirty[owner.String()]; ok { 394 return d.Clone() 395 } 396 return nil 397 } 398 399 func (cc *candChange) getBySelfStakingIndex(index uint64) *Candidate { 400 for _, d := range cc.dirty { 401 if d.isSelfStakeBucketSettled() && index == d.SelfStakeBucketIdx { 402 return d.Clone() 403 } 404 } 405 return nil 406 } 407 408 func (cc *candChange) upsert(d *Candidate) error { 409 if err := d.Validate(); err != nil { 410 return err 411 } 412 cc.candidates = append(cc.candidates, d) 413 cc.dirty[d.Owner.String()] = d 414 return nil 415 } 416 417 func (cc *candChange) collision(d *Candidate) error { 418 for _, c := range cc.dirty { 419 if err := d.Collision(c); err != nil { 420 return err 421 } 422 } 423 return nil 424 } 425 426 //====================================== 427 // candBase funcs 428 //====================================== 429 430 func newCandBase() *candBase { 431 return &candBase{ 432 nameMap: make(map[string]*Candidate), 433 ownerMap: make(map[string]*Candidate), 434 operatorMap: make(map[string]*Candidate), 435 selfStkBucketMap: make(map[uint64]*Candidate), 436 } 437 } 438 439 func (cb *candBase) size() int { 440 cb.lock.RLock() 441 defer cb.lock.RUnlock() 442 return len(cb.ownerMap) 443 } 444 445 func (cb *candBase) all() CandidateList { 446 cb.lock.RLock() 447 defer cb.lock.RUnlock() 448 if len(cb.ownerMap) == 0 { 449 return nil 450 } 451 452 list := make(CandidateList, 0, len(cb.ownerMap)) 453 for _, d := range cb.ownerMap { 454 list = append(list, d.Clone()) 455 } 456 return list 457 } 458 459 func (cb *candBase) commit(change *candChange, keepAliasBug bool) (int, error) { 460 cb.lock.Lock() 461 defer cb.lock.Unlock() 462 if keepAliasBug { 463 for _, v := range change.dirty { 464 if err := v.Validate(); err != nil { 465 return 0, err 466 } 467 d := v.Clone() 468 cb.ownerMap[d.Owner.String()] = d 469 cb.nameMap[d.Name] = d 470 cb.operatorMap[d.Operator.String()] = d 471 cb.selfStkBucketMap[d.SelfStakeBucketIdx] = d 472 } 473 } else { 474 for _, v := range change.candidates { 475 if err := v.Validate(); err != nil { 476 return 0, err 477 } 478 d := v.Clone() 479 if curr, ok := cb.ownerMap[d.Owner.String()]; ok { 480 delete(cb.nameMap, curr.Name) 481 delete(cb.operatorMap, curr.Operator.String()) 482 delete(cb.selfStkBucketMap, curr.SelfStakeBucketIdx) 483 } 484 cb.ownerMap[d.Owner.String()] = d 485 cb.nameMap[d.Name] = d 486 cb.operatorMap[d.Operator.String()] = d 487 if d.isSelfStakeBucketSettled() { 488 cb.selfStkBucketMap[d.SelfStakeBucketIdx] = d 489 } 490 } 491 } 492 return len(cb.ownerMap), nil 493 } 494 495 func (cb *candBase) getByName(name string) (*Candidate, bool) { 496 cb.lock.RLock() 497 defer cb.lock.RUnlock() 498 d, ok := cb.nameMap[name] 499 return d, ok 500 } 501 502 func (cb *candBase) getByOwner(name string) (*Candidate, bool) { 503 cb.lock.RLock() 504 defer cb.lock.RUnlock() 505 d, ok := cb.ownerMap[name] 506 return d, ok 507 } 508 509 func (cb *candBase) getByOperator(name string) (*Candidate, bool) { 510 cb.lock.RLock() 511 defer cb.lock.RUnlock() 512 d, ok := cb.operatorMap[name] 513 return d, ok 514 } 515 516 func (cb *candBase) getBySelfStakingIndex(index uint64) (*Candidate, bool) { 517 cb.lock.RLock() 518 defer cb.lock.RUnlock() 519 d, ok := cb.selfStkBucketMap[index] 520 return d, ok 521 } 522 523 func (cb *candBase) collision(d *Candidate) (address.Address, address.Address, address.Address) { 524 cb.lock.RLock() 525 defer cb.lock.RUnlock() 526 var name, oper, self address.Address 527 if c, hit := cb.nameMap[d.Name]; hit && !address.Equal(c.Owner, d.Owner) { 528 name = c.Owner 529 } 530 531 if c, hit := cb.operatorMap[d.Operator.String()]; hit && !address.Equal(c.Owner, d.Owner) { 532 oper = c.Owner 533 } 534 535 if c, hit := cb.selfStkBucketMap[d.SelfStakeBucketIdx]; hit && !address.Equal(c.Owner, d.Owner) { 536 self = c.Owner 537 } 538 return name, oper, self 539 } 540 541 func (cb *candBase) delete(owner address.Address) { 542 cb.lock.Lock() 543 defer cb.lock.Unlock() 544 if d, hit := cb.ownerMap[owner.String()]; hit { 545 delete(cb.nameMap, d.Name) 546 delete(cb.ownerMap, d.Owner.String()) 547 delete(cb.operatorMap, d.Operator.String()) 548 delete(cb.selfStkBucketMap, d.SelfStakeBucketIdx) 549 } 550 }