github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/poll/candidateindexer.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 poll
     7  
     8  import (
     9  	"context"
    10  	"sync"
    11  
    12  	"github.com/pkg/errors"
    13  	"go.uber.org/zap"
    14  
    15  	"github.com/iotexproject/iotex-core/action/protocol/vote"
    16  	"github.com/iotexproject/iotex-core/db"
    17  	"github.com/iotexproject/iotex-core/pkg/log"
    18  	"github.com/iotexproject/iotex-core/pkg/util/byteutil"
    19  	"github.com/iotexproject/iotex-core/state"
    20  )
    21  
    22  var (
    23  	// CandidateNamespace is a namespace to store raw candidate
    24  	CandidateNamespace = "candidates"
    25  	// ProbationNamespace is a namespace to store probationlist
    26  	ProbationNamespace = "kickout"
    27  	// ErrIndexerNotExist is an error that shows not exist in candidate indexer DB
    28  	ErrIndexerNotExist = errors.New("not exist in DB")
    29  )
    30  
    31  // CandidateIndexer is an indexer to store candidate/probationList by given height
    32  type CandidateIndexer struct {
    33  	mutex   sync.RWMutex
    34  	kvStore db.KVStore
    35  }
    36  
    37  // NewCandidateIndexer creates a new CandidateIndexer
    38  func NewCandidateIndexer(kv db.KVStore) (*CandidateIndexer, error) {
    39  	if kv == nil {
    40  		return nil, errors.New("empty kvStore")
    41  	}
    42  	x := CandidateIndexer{
    43  		kvStore: kv,
    44  	}
    45  	return &x, nil
    46  }
    47  
    48  // Start starts the indexer
    49  func (cd *CandidateIndexer) Start(ctx context.Context) error {
    50  	return cd.kvStore.Start(ctx)
    51  }
    52  
    53  // Stop stops the indexer
    54  func (cd *CandidateIndexer) Stop(ctx context.Context) error {
    55  	return cd.kvStore.Stop(ctx)
    56  }
    57  
    58  // PutCandidateList puts candidate list into indexer
    59  func (cd *CandidateIndexer) PutCandidateList(height uint64, candidates *state.CandidateList) error {
    60  	cd.mutex.Lock()
    61  	defer cd.mutex.Unlock()
    62  	candidatesByte, err := candidates.Serialize()
    63  	if err != nil {
    64  		return err
    65  	}
    66  	log.L().Debug("put candidatelist into candidate indexer", zap.Uint64("height", height))
    67  	return cd.kvStore.Put(CandidateNamespace, byteutil.Uint64ToBytes(height), candidatesByte)
    68  }
    69  
    70  // PutProbationList puts probation list into indexer
    71  func (cd *CandidateIndexer) PutProbationList(height uint64, probationList *vote.ProbationList) error {
    72  	cd.mutex.Lock()
    73  	defer cd.mutex.Unlock()
    74  	probationListByte, err := probationList.Serialize()
    75  	if err != nil {
    76  		return err
    77  	}
    78  	log.L().Debug("put probation list into candidate indexer", zap.Uint64("height", height))
    79  	return cd.kvStore.Put(ProbationNamespace, byteutil.Uint64ToBytes(height), probationListByte)
    80  }
    81  
    82  // CandidateList gets candidate list from indexer given epoch start height
    83  func (cd *CandidateIndexer) CandidateList(height uint64) (state.CandidateList, error) {
    84  	cd.mutex.RLock()
    85  	defer cd.mutex.RUnlock()
    86  	log.L().Debug("get candidatelist from candidate indexer", zap.Uint64("height", height))
    87  	candidates := &state.CandidateList{}
    88  	bytes, err := cd.kvStore.Get(CandidateNamespace, byteutil.Uint64ToBytes(height))
    89  	if err != nil {
    90  		if errors.Cause(err) == db.ErrNotExist {
    91  			log.L().Debug(
    92  				"failed to read candidates from indexer because does not exist",
    93  				zap.Uint64("epoch height", height),
    94  			)
    95  			return nil, ErrIndexerNotExist
    96  		}
    97  		return nil, err
    98  	}
    99  	if err := candidates.Deserialize(bytes); err != nil {
   100  		return nil, err
   101  	}
   102  	return *candidates, nil
   103  }
   104  
   105  // ProbationList gets probation list from indexer given epoch start height
   106  func (cd *CandidateIndexer) ProbationList(height uint64) (*vote.ProbationList, error) {
   107  	cd.mutex.RLock()
   108  	defer cd.mutex.RUnlock()
   109  	log.L().Debug("get probationlist from candidate indexer", zap.Uint64("height", height))
   110  	bl := &vote.ProbationList{}
   111  	bytes, err := cd.kvStore.Get(ProbationNamespace, byteutil.Uint64ToBytes(height))
   112  	if err != nil {
   113  		if errors.Cause(err) == db.ErrNotExist {
   114  			log.L().Debug(
   115  				"failed to probation list from indexer because does not exist",
   116  				zap.Uint64("epoch height", height),
   117  			)
   118  			return nil, ErrIndexerNotExist
   119  		}
   120  		return nil, err
   121  	}
   122  	if err := bl.Deserialize(bytes); err != nil {
   123  		return nil, err
   124  	}
   125  	return bl, nil
   126  }