github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/staking/candidate_statemanager.go (about) 1 // Copyright (c) 2022 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 "context" 10 "math/big" 11 12 "github.com/pkg/errors" 13 14 "github.com/iotexproject/iotex-address/address" 15 16 "github.com/iotexproject/iotex-core/action/protocol" 17 "github.com/iotexproject/iotex-core/state" 18 ) 19 20 // const 21 const ( 22 _stakingCandCenter = "candCenter" 23 ) 24 25 type ( 26 // BucketSet related to setting bucket 27 BucketSet interface { 28 updateBucket(index uint64, bucket *VoteBucket) error 29 putBucket(bucket *VoteBucket) (uint64, error) 30 delBucket(index uint64) error 31 putBucketAndIndex(bucket *VoteBucket) (uint64, error) 32 delBucketAndIndex(owner, cand address.Address, index uint64) error 33 } 34 // CandidateSet related to setting candidates 35 CandidateSet interface { 36 putCandidate(*Candidate) error 37 delCandidate(address.Address) error 38 putVoterBucketIndex(address.Address, uint64) error 39 delVoterBucketIndex(address.Address, uint64) error 40 putCandBucketIndex(address.Address, uint64) error 41 delCandBucketIndex(address.Address, uint64) error 42 } 43 // CandidateStateManager is candidate state manager on top of StateManager 44 CandidateStateManager interface { 45 BucketSet 46 BucketGetByIndex 47 CandidateSet 48 // candidate and bucket pool related 49 DirtyView() *ViewData 50 ContainsName(string) bool 51 ContainsOwner(address.Address) bool 52 ContainsOperator(address.Address) bool 53 ContainsSelfStakingBucket(uint64) bool 54 GetByName(string) *Candidate 55 GetByOwner(address.Address) *Candidate 56 Upsert(*Candidate) error 57 CreditBucketPool(*big.Int) error 58 DebitBucketPool(*big.Int, bool) error 59 Commit(context.Context) error 60 SM() protocol.StateManager 61 SR() protocol.StateReader 62 } 63 64 // CandidiateStateCommon is the common interface for candidate state manager and reader 65 CandidiateStateCommon interface { 66 ContainsSelfStakingBucket(uint64) bool 67 SR() protocol.StateReader 68 } 69 70 candSM struct { 71 protocol.StateManager 72 candCenter *CandidateCenter 73 bucketPool *BucketPool 74 } 75 ) 76 77 // NewCandidateStateManager returns a new CandidateStateManager instance 78 func NewCandidateStateManager(sm protocol.StateManager, enableSMStorage bool) (CandidateStateManager, error) { 79 // TODO: we can store csm in a local cache, just as how statedb store the workingset 80 // b/c most time the sm is used before, no need to create another clone 81 csr, err := ConstructBaseView(sm) 82 if err != nil { 83 return nil, err 84 } 85 86 // make a copy of candidate center and bucket pool, so they can be modified by csm 87 // and won't affect base view until being committed 88 view := csr.BaseView() 89 csm := &candSM{ 90 StateManager: sm, 91 candCenter: view.candCenter.Base(), 92 bucketPool: view.bucketPool.Copy(enableSMStorage), 93 } 94 95 // extract view change from SM 96 if err := csm.bucketPool.Sync(sm); err != nil { 97 return nil, errors.Wrap(err, "failed to sync bucket pool") 98 } 99 100 if err := csm.candCenter.Sync(sm); err != nil { 101 return nil, errors.Wrap(err, "failed to sync candidate center") 102 } 103 return csm, nil 104 } 105 106 func newCandidateStateManager(sm protocol.StateManager) CandidateStateManager { 107 return &candSM{ 108 StateManager: sm, 109 } 110 } 111 112 func (csm *candSM) SM() protocol.StateManager { 113 return csm.StateManager 114 } 115 116 func (csm *candSM) SR() protocol.StateReader { 117 return csm.StateManager 118 } 119 120 // DirtyView is csm's current state, which reflects base view + applying delta saved in csm's dock 121 func (csm *candSM) DirtyView() *ViewData { 122 return &ViewData{ 123 candCenter: csm.candCenter, 124 bucketPool: csm.bucketPool, 125 } 126 } 127 128 func (csm *candSM) ContainsName(name string) bool { 129 return csm.candCenter.ContainsName(name) 130 } 131 132 func (csm *candSM) ContainsOwner(addr address.Address) bool { 133 return csm.candCenter.ContainsOwner(addr) 134 } 135 136 func (csm *candSM) ContainsOperator(addr address.Address) bool { 137 return csm.candCenter.ContainsOperator(addr) 138 } 139 140 func (csm *candSM) ContainsSelfStakingBucket(index uint64) bool { 141 return csm.candCenter.ContainsSelfStakingBucket(index) 142 } 143 144 func (csm *candSM) GetByName(name string) *Candidate { 145 return csm.candCenter.GetByName(name) 146 } 147 148 func (csm *candSM) GetByOwner(addr address.Address) *Candidate { 149 return csm.candCenter.GetByOwner(addr) 150 } 151 152 // Upsert writes the candidate into state manager and cand center 153 func (csm *candSM) Upsert(d *Candidate) error { 154 if err := csm.candCenter.Upsert(d); err != nil { 155 return err 156 } 157 158 if err := csm.putCandidate(d); err != nil { 159 return err 160 } 161 162 delta := csm.candCenter.Delta() 163 if len(delta) == 0 { 164 return nil 165 } 166 167 // load change to sm 168 return csm.StateManager.Load(_protocolID, _stakingCandCenter, &delta) 169 } 170 171 func (csm *candSM) CreditBucketPool(amount *big.Int) error { 172 return csm.bucketPool.CreditPool(csm.StateManager, amount) 173 } 174 175 func (csm *candSM) DebitBucketPool(amount *big.Int, newBucket bool) error { 176 return csm.bucketPool.DebitPool(csm, amount, newBucket) 177 } 178 179 func (csm *candSM) Commit(ctx context.Context) error { 180 height, err := csm.Height() 181 if err != nil { 182 return err 183 } 184 if featureWithHeightCtx, ok := protocol.GetFeatureWithHeightCtx(ctx); ok && featureWithHeightCtx.CandCenterHasAlias(height) { 185 if err := csm.candCenter.LegacyCommit(); err != nil { 186 return err 187 } 188 } else { 189 if err := csm.candCenter.Commit(); err != nil { 190 return err 191 } 192 } 193 194 if err := csm.bucketPool.Commit(csm); err != nil { 195 return err 196 } 197 198 // write updated view back to state factory 199 return csm.WriteView(_protocolID, csm.DirtyView()) 200 } 201 202 func (csm *candSM) getBucket(index uint64) (*VoteBucket, error) { 203 return newCandidateStateReader(csm).getBucket(index) 204 } 205 206 func (csm *candSM) updateBucket(index uint64, bucket *VoteBucket) error { 207 if _, err := csm.getBucket(index); err != nil { 208 return err 209 } 210 211 _, err := csm.PutState( 212 bucket, 213 protocol.NamespaceOption(_stakingNameSpace), 214 protocol.KeyOption(bucketKey(index))) 215 return err 216 } 217 218 func (csm *candSM) putBucket(bucket *VoteBucket) (uint64, error) { 219 var tc totalBucketCount 220 if _, err := csm.State( 221 &tc, 222 protocol.NamespaceOption(_stakingNameSpace), 223 protocol.KeyOption(TotalBucketKey)); err != nil && errors.Cause(err) != state.ErrStateNotExist { 224 return 0, err 225 } 226 227 index := tc.Count() 228 // Add index inside bucket 229 bucket.Index = index 230 if _, err := csm.PutState( 231 bucket, 232 protocol.NamespaceOption(_stakingNameSpace), 233 protocol.KeyOption(bucketKey(index))); err != nil { 234 return 0, err 235 } 236 tc.count++ 237 _, err := csm.PutState( 238 &tc, 239 protocol.NamespaceOption(_stakingNameSpace), 240 protocol.KeyOption(TotalBucketKey)) 241 return index, err 242 } 243 244 func (csm *candSM) delBucket(index uint64) error { 245 _, err := csm.DelState( 246 protocol.NamespaceOption(_stakingNameSpace), 247 protocol.KeyOption(bucketKey(index))) 248 return err 249 } 250 251 func (csm *candSM) putBucketAndIndex(bucket *VoteBucket) (uint64, error) { 252 index, err := csm.putBucket(bucket) 253 if err != nil { 254 return 0, errors.Wrap(err, "failed to put bucket") 255 } 256 257 if err := csm.putVoterBucketIndex(bucket.Owner, index); err != nil { 258 return 0, errors.Wrap(err, "failed to put bucket index") 259 } 260 261 if err := csm.putCandBucketIndex(bucket.Candidate, index); err != nil { 262 return 0, errors.Wrap(err, "failed to put candidate index") 263 } 264 return index, nil 265 } 266 267 func (csm *candSM) delBucketAndIndex(owner, cand address.Address, index uint64) error { 268 if err := csm.delBucket(index); err != nil { 269 return errors.Wrap(err, "failed to delete bucket") 270 } 271 272 if err := csm.delVoterBucketIndex(owner, index); err != nil { 273 return errors.Wrap(err, "failed to delete bucket index") 274 } 275 276 if err := csm.delCandBucketIndex(cand, index); err != nil { 277 return errors.Wrap(err, "failed to delete candidate index") 278 } 279 return nil 280 } 281 282 func (csm *candSM) putBucketIndex(addr address.Address, prefix byte, index uint64) error { 283 var ( 284 bis BucketIndices 285 key = AddrKeyWithPrefix(addr, prefix) 286 ) 287 if _, err := csm.State( 288 &bis, 289 protocol.NamespaceOption(_stakingNameSpace), 290 protocol.KeyOption(key)); err != nil && errors.Cause(err) != state.ErrStateNotExist { 291 return err 292 } 293 bis.addBucketIndex(index) 294 _, err := csm.PutState( 295 &bis, 296 protocol.NamespaceOption(_stakingNameSpace), 297 protocol.KeyOption(key)) 298 return err 299 } 300 301 func (csm *candSM) putVoterBucketIndex(addr address.Address, index uint64) error { 302 return csm.putBucketIndex(addr, _voterIndex, index) 303 } 304 305 func (csm *candSM) delBucketIndex(addr address.Address, prefix byte, index uint64) error { 306 var ( 307 bis BucketIndices 308 key = AddrKeyWithPrefix(addr, prefix) 309 ) 310 if _, err := csm.State( 311 &bis, 312 protocol.NamespaceOption(_stakingNameSpace), 313 protocol.KeyOption(key)); err != nil { 314 return err 315 } 316 bis.deleteBucketIndex(index) 317 318 var err error 319 if len(bis) == 0 { 320 _, err = csm.DelState( 321 protocol.NamespaceOption(_stakingNameSpace), 322 protocol.KeyOption(key)) 323 } else { 324 _, err = csm.PutState( 325 &bis, 326 protocol.NamespaceOption(_stakingNameSpace), 327 protocol.KeyOption(key)) 328 } 329 return err 330 } 331 332 func (csm *candSM) delVoterBucketIndex(addr address.Address, index uint64) error { 333 return csm.delBucketIndex(addr, _voterIndex, index) 334 } 335 336 func (csm *candSM) putCandidate(d *Candidate) error { 337 _, err := csm.PutState(d, protocol.NamespaceOption(_candidateNameSpace), protocol.KeyOption(d.Owner.Bytes())) 338 return err 339 } 340 341 func (csm *candSM) putCandBucketIndex(addr address.Address, index uint64) error { 342 return csm.putBucketIndex(addr, _candIndex, index) 343 } 344 345 func (csm *candSM) delCandidate(name address.Address) error { 346 _, err := csm.DelState(protocol.NamespaceOption(_candidateNameSpace), protocol.KeyOption(name.Bytes())) 347 return err 348 } 349 350 func (csm *candSM) delCandBucketIndex(addr address.Address, index uint64) error { 351 return csm.delBucketIndex(addr, _candIndex, index) 352 }