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 }