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  }