github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dbft/backend/snapshot.go (about) 1 package backend 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "encoding/json" 7 "errors" 8 "fmt" 9 "math/big" 10 "sort" 11 12 "github.com/quickchainproject/quickchain/common" 13 bft "github.com/quickchainproject/quickchain/consensus/dbft" 14 "github.com/quickchainproject/quickchain/consensus/dbft/validator" 15 "github.com/quickchainproject/quickchain/core/state" 16 "github.com/quickchainproject/quickchain/core/types" 17 "github.com/quickchainproject/quickchain/qctdb" 18 "github.com/quickchainproject/quickchain/log" 19 "github.com/quickchainproject/quickchain/rlp" 20 "github.com/quickchainproject/quickchain/trie" 21 ) 22 23 const ( 24 dbKeySnapshotPrefix = "dbft-snapshot" 25 ) 26 27 // Vote represents a single vote that an authorized validator made to modify the 28 // list of authorizations. 29 type Vote struct { 30 Validator common.Address `json:"validator"` // Authorized validator that cast this vote 31 Block uint64 `json:"block"` // Block number the vote was cast in (expire old votes) 32 Address common.Address `json:"address"` // Account being voted on to change its authorization 33 Authorize bool `json:"authorize"` // Whether to authorize or deauthorize the voted account 34 } 35 36 // Tally is a simple vote tally to keep the current score of votes. Votes that 37 // go against the proposal aren't counted since it's equivalent to not voting. 38 type Tally struct { 39 Authorize bool `json:"authorize"` // Whether the vote it about authorizing or kicking someone 40 Votes int `json:"votes"` // Number of votes until now wanting to pass the proposal 41 } 42 43 // Snapshot is the state of the authorization voting at a given point in time. 44 type Snapshot struct { 45 Epoch uint64 // The number of blocks after which to checkpoint and reset the pending votes 46 47 Number uint64 // Block number where the snapshot was created 48 Hash common.Hash // Block hash where the snapshot was created 49 Votes []*Vote // List of votes cast in chronological order 50 Tally map[common.Address]Tally // Current vote tally to avoid recalculating 51 ValSet bft.ValidatorSet // Set of authorized validators at this moment 52 53 DposContext *types.DposContext 54 StateDB *state.StateDB 55 } 56 57 // newSnapshot create a new snapshot with the specified startup parameters. This 58 // method does not initialize the set of recent validators, so only ever use if for 59 // the genesis block. 60 func newSnapshot(epoch uint64, number uint64, hash common.Hash, valSet bft.ValidatorSet, dposContext *types.DposContext, state *state.StateDB) *Snapshot { 61 snap := &Snapshot{ 62 Epoch: epoch, 63 Number: number, 64 Hash: hash, 65 ValSet: valSet.Copy(), 66 Tally: make(map[common.Address]Tally), 67 68 DposContext: dposContext.Copy(), 69 StateDB: state, 70 } 71 72 size := valSet.Size() 73 snap.ValSet = valSet.Copy() 74 75 addrs := make([]common.Address, 0) 76 for i := 0; i < size; i++ { 77 addr := snap.ValSet.GetByIndex(uint64(i)).Address() 78 addrs = append(addrs, addr) 79 } 80 81 for _, addr := range addrs { 82 snap.ValSet.RemoveValidator(addr) 83 } 84 85 if snap.ValSet.Size() > 0 { 86 log.Error("RemoveAllValidators err", "size", snap.ValSet.Size()) 87 } 88 89 // get signer list 90 validators, err := dposContext.GetValidators() 91 log.Info("dposValidators", "size", len(validators)) 92 if err != nil { 93 return nil 94 } 95 96 for _, signer := range validators { 97 snap.ValSet.AddValidator(signer) 98 } 99 100 return snap 101 } 102 103 // loadSnapshot loads an existing snapshot from the database. 104 func loadSnapshot(epoch uint64, db qctdb.Database, hash common.Hash) (*Snapshot, error) { 105 blob, err := db.Get(append([]byte(dbKeySnapshotPrefix), hash[:]...)) 106 if err != nil { 107 return nil, err 108 } 109 snap := new(Snapshot) 110 if err := json.Unmarshal(blob, snap); err != nil { 111 return nil, err 112 } 113 snap.Epoch = epoch 114 115 return snap, nil 116 } 117 118 // store inserts the snapshot into the database. 119 func (s *Snapshot) store(db qctdb.Database) error { 120 blob, err := json.Marshal(s) 121 if err != nil { 122 return err 123 } 124 return db.Put(append([]byte(dbKeySnapshotPrefix), s.Hash[:]...), blob) 125 } 126 127 // copy creates a deep copy of the snapshot, though not the individual votes. 128 func (s *Snapshot) copy() *Snapshot { 129 cpy := &Snapshot{ 130 Epoch: s.Epoch, 131 Number: s.Number, 132 Hash: s.Hash, 133 ValSet: s.ValSet.Copy(), 134 Votes: make([]*Vote, len(s.Votes)), 135 Tally: make(map[common.Address]Tally), 136 137 // DposContext: s.DposContext.Copy(), 138 // StateDB: s.StateDB.Copy(),//FIXME 139 } 140 141 for address, tally := range s.Tally { 142 cpy.Tally[address] = tally 143 } 144 copy(cpy.Votes, s.Votes) 145 146 cpy.DposContext = &types.DposContext{} 147 if s.DposContext != nil { 148 cpy.DposContext = s.DposContext.Copy() 149 } 150 151 return cpy 152 } 153 154 // checkVote return whether it's a valid vote 155 func (s *Snapshot) checkVote(address common.Address, authorize bool) bool { 156 _, validator := s.ValSet.GetByAddress(address) 157 return (validator != nil && !authorize) || (validator == nil && authorize) 158 } 159 160 // cast adds a new vote into the tally. 161 func (s *Snapshot) cast(address common.Address, authorize bool) bool { 162 // Ensure the vote is meaningful 163 if !s.checkVote(address, authorize) { 164 return false 165 } 166 // Cast the vote into an existing or new tally 167 if old, ok := s.Tally[address]; ok { 168 old.Votes++ 169 s.Tally[address] = old 170 } else { 171 s.Tally[address] = Tally{Authorize: authorize, Votes: 1} 172 } 173 return true 174 } 175 176 // uncast removes a previously cast vote from the tally. 177 func (s *Snapshot) uncast(address common.Address, authorize bool) bool { 178 // If there's no tally, it's a dangling vote, just drop 179 tally, ok := s.Tally[address] 180 if !ok { 181 return false 182 } 183 // Ensure we only revert counted votes 184 if tally.Authorize != authorize { 185 return false 186 } 187 // Otherwise revert the vote 188 if tally.Votes > 1 { 189 tally.Votes-- 190 s.Tally[address] = tally 191 } else { 192 delete(s.Tally, address) 193 } 194 return true 195 } 196 197 // apply creates a new authorization snapshot by applying the given headers to 198 // the original one. 199 func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { 200 // Allow passing in no headers for cleaner code 201 if len(headers) == 0 { 202 return s, nil 203 } 204 // Sanity check that the headers can be applied 205 for i := 0; i < len(headers)-1; i++ { 206 if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 { 207 return nil, errInvalidVotingChain 208 } 209 } 210 if headers[0].Number.Uint64() != s.Number+1 { 211 return nil, errInvalidVotingChain 212 } 213 // Iterate through the headers and create a new snapshot 214 snap := s.copy() 215 216 for _, header := range headers { 217 // Remove any votes on checkpoint blocks 218 number := header.Number.Uint64() 219 if number%s.Epoch == 0 { 220 snap.Votes = nil 221 snap.Tally = make(map[common.Address]Tally) 222 } 223 // Resolve the authorization key and check against validators 224 validator, err := ecrecover(header, recentAddresses) 225 if err != nil { 226 return nil, err 227 } 228 if _, v := snap.ValSet.GetByAddress(validator); v == nil { 229 log.Error("apply", "validator", validator, "valSet", snap.ValSet) 230 return nil, errUnauthorized 231 } 232 233 /* 234 // Header authorized, discard any previous votes from the validator 235 for i, vote := range snap.Votes { 236 if vote.Validator == validator && vote.Address == header.Coinbase { 237 // Uncast the vote from the cached tally 238 snap.uncast(vote.Address, vote.Authorize) 239 240 // Uncast the vote from the chronological list 241 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 242 break // only one vote allowed 243 } 244 } 245 // Tally up the new vote from the validator 246 var authorize bool 247 switch { 248 case bytes.Compare(header.Nonce[:], nonceAuthVote) == 0: 249 authorize = true 250 case bytes.Compare(header.Nonce[:], nonceDropVote) == 0: 251 authorize = false 252 default: 253 return nil, errInvalidVote 254 } 255 if snap.cast(header.Coinbase, authorize) { 256 snap.Votes = append(snap.Votes, &Vote{ 257 Validator: validator, 258 Block: number, 259 Address: header.Coinbase, 260 Authorize: authorize, 261 }) 262 } 263 // If the vote passed, update the list of validators 264 if tally := snap.Tally[header.Coinbase]; tally.Votes > snap.ValSet.Size()/2 { 265 if tally.Authorize { 266 snap.ValSet.AddValidator(header.Coinbase) 267 } else { 268 snap.ValSet.RemoveValidator(header.Coinbase) 269 270 // Discard any previous votes the deauthorized validator cast 271 for i := 0; i < len(snap.Votes); i++ { 272 if snap.Votes[i].Validator == header.Coinbase { 273 // Uncast the vote from the cached tally 274 snap.uncast(snap.Votes[i].Address, snap.Votes[i].Authorize) 275 276 // Uncast the vote from the chronological list 277 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 278 279 i-- 280 } 281 } 282 } 283 // Discard any previous votes around the just changed account 284 for i := 0; i < len(snap.Votes); i++ { 285 if snap.Votes[i].Address == header.Coinbase { 286 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 287 i-- 288 } 289 } 290 delete(snap.Tally, header.Coinbase) 291 } 292 */ 293 } 294 snap.Number += uint64(len(headers)) 295 snap.Hash = headers[len(headers)-1].Hash() 296 297 return snap, nil 298 } 299 300 // validators retrieves the list of authorized validators in ascending order. 301 func (s *Snapshot) validators() []common.Address { 302 validators := make([]common.Address, 0, s.ValSet.Size()) 303 for _, validator := range s.ValSet.List() { 304 validators = append(validators, validator.Address()) 305 } 306 for i := 0; i < len(validators); i++ { 307 for j := i + 1; j < len(validators); j++ { 308 if bytes.Compare(validators[i][:], validators[j][:]) > 0 { 309 validators[i], validators[j] = validators[j], validators[i] 310 } 311 } 312 } 313 return validators 314 } 315 316 type snapshotJSON struct { 317 Epoch uint64 `json:"epoch"` 318 Number uint64 `json:"number"` 319 Hash common.Hash `json:"hash"` 320 Votes []*Vote `json:"votes"` 321 Tally map[common.Address]Tally `json:"tally"` 322 323 // for validator set 324 Validators []common.Address `json:"validators"` 325 Policy bft.ProposerPolicy `json:"policy"` 326 327 // for dpos 328 DposContext *types.DposContext `json:"dposcontext"` 329 StateDB *state.StateDB `json:"statedb"` 330 } 331 332 func (s *Snapshot) toJSONStruct() *snapshotJSON { 333 return &snapshotJSON{ 334 Epoch: s.Epoch, 335 Number: s.Number, 336 Hash: s.Hash, 337 Votes: s.Votes, 338 Tally: s.Tally, 339 Validators: s.validators(), 340 Policy: s.ValSet.Policy(), 341 342 DposContext: s.DposContext, 343 StateDB: s.StateDB, 344 } 345 } 346 347 // Unmarshal from a json byte array 348 func (s *Snapshot) UnmarshalJSON(b []byte) error { 349 var j snapshotJSON 350 if err := json.Unmarshal(b, &j); err != nil { 351 return err 352 } 353 354 s.Epoch = j.Epoch 355 s.Number = j.Number 356 s.Hash = j.Hash 357 s.Votes = j.Votes 358 s.Tally = j.Tally 359 s.ValSet = validator.NewSet(j.Validators, j.Policy) 360 361 s.DposContext = j.DposContext 362 s.StateDB = j.StateDB 363 return nil 364 } 365 366 // Marshal to a json byte array 367 func (s *Snapshot) MarshalJSON() ([]byte, error) { 368 j := s.toJSONStruct() 369 return json.Marshal(j) 370 } 371 372 // countVotes 373 func (ec *Snapshot) countVotes() (votes map[common.Address]*big.Int, err error) { 374 votes = map[common.Address]*big.Int{} 375 delegateTrie := ec.DposContext.DelegateTrie() 376 candidateTrie := ec.DposContext.CandidateTrie() 377 statedb := ec.StateDB 378 379 iterCandidate := trie.NewIterator(candidateTrie.NodeIterator(nil)) 380 existCandidate := iterCandidate.Next() 381 if !existCandidate { 382 return votes, errors.New("no candidates") 383 } 384 for existCandidate { 385 var cc types.CandidateContext 386 candidate := iterCandidate.Value 387 rlp.DecodeBytes(candidate, &cc) 388 candidateAddr := common.BytesToAddress(cc.Addr.Bytes()) 389 //delegateIterator := trie.NewIterator(delegateTrie.PrefixIterator(candidate)) 390 delegateIterator := trie.NewIterator(delegateTrie.PrefixIterator(cc.Addr.Bytes())) 391 existDelegator := delegateIterator.Next() 392 if !existDelegator { 393 log.Info("-------!existDelegator", "candidate", candidateAddr) 394 votes[candidateAddr] = new(big.Int) 395 existCandidate = iterCandidate.Next() 396 continue 397 } 398 for existDelegator { 399 log.Info("-------existDelegator", "candidate", candidateAddr) 400 delegator := delegateIterator.Value 401 score, ok := votes[candidateAddr] 402 if !ok { 403 score = new(big.Int) 404 } 405 delegatorAddr := common.BytesToAddress(delegator) 406 weight := statedb.GetBalance(delegatorAddr) 407 score.Add(score, weight) 408 votes[candidateAddr] = score 409 existDelegator = delegateIterator.Next() 410 } 411 existCandidate = iterCandidate.Next() 412 } 413 for k, v := range votes { 414 log.Info("votes:", "k", k, "v", v) 415 } 416 return votes, nil 417 } 418 419 // CommitScores commit candidate score into candidate tree in every epoch elec process 420 func (ec *Snapshot) CommitScores(scores map[common.Address]*big.Int) error { 421 for k, v := range scores { 422 cc, err := ec.DposContext.GetCandidateContext(k) 423 if err != nil { 424 return err 425 } 426 if bytes.Compare(cc.Addr.Bytes(), k.Bytes()) == 0 { 427 cc.Score = v 428 err = ec.DposContext.SetCandidateContext(cc) 429 if err != nil { 430 return err 431 } 432 } 433 } 434 return nil 435 } 436 437 func (ec *Snapshot) kickoutValidator() error { 438 validators, err := ec.DposContext.GetValidators() 439 if err != nil { 440 return fmt.Errorf("failed to get validator: %s", err) 441 } 442 if len(validators) == 0 { 443 return errors.New("no validator could be kickout") 444 } 445 446 needKickoutValidators := types.SortableAddresses{} 447 for _, validator := range validators { 448 449 key := validator.Bytes() 450 cnt := int64(0) 451 if cntBytes := ec.DposContext.MintCntTrie().Get(key); cntBytes != nil { 452 cnt = int64(binary.BigEndian.Uint64(cntBytes)) 453 } 454 if cnt < int64(epochLength)/maxValidatorSize/2 { 455 // not active validators need kickout 456 needKickoutValidators = append(needKickoutValidators, &types.SortableAddress{Address: validator, Weight: big.NewInt(cnt)}) 457 } 458 } 459 // clear mintcnt trie 460 mintCntTrie, _ := types.NewMintCntTrie(common.Hash{}, ec.DposContext.DB()) 461 ec.DposContext.SetMintCnt(mintCntTrie) 462 463 // no validators need kickout 464 needKickoutValidatorCnt := len(needKickoutValidators) 465 if needKickoutValidatorCnt <= 0 { 466 return nil 467 } 468 sort.Sort(sort.Reverse(needKickoutValidators)) 469 470 candidateCount := 0 471 iter := trie.NewIterator(ec.DposContext.CandidateTrie().NodeIterator(nil)) 472 for iter.Next() { 473 candidateCount++ 474 if candidateCount >= needKickoutValidatorCnt+safeSize { 475 break 476 } 477 } 478 479 for i, validator := range needKickoutValidators { 480 // ensure candidate count greater than or equal to safeSize 481 if candidateCount <= safeSize { 482 log.Info("No more candidate can be kickout", "candidateCount", candidateCount, "needKickoutCount", len(needKickoutValidators)-i) 483 return nil 484 } 485 486 if err := ec.DposContext.KickoutCandidate(validator.Address); err != nil { 487 return err 488 } 489 // if kickout success, candidateCount minus 1 490 candidateCount-- 491 log.Info("Kickout candidate", "candidate", validator.Address.String(), "mintCnt", validator.Weight.String()) 492 } 493 return nil 494 } 495 496 // update counts in MintCntTrie for the miner of newBlock 497 func (ec *Snapshot) updateMintCnt(validator common.Address) { 498 currentMintCntTrie := ec.DposContext.MintCntTrie() 499 500 cnt := int64(1) 501 502 cntBytes := currentMintCntTrie.Get(validator.Bytes()) 503 504 // not the first time to mint 505 if cntBytes != nil { 506 cnt = int64(binary.BigEndian.Uint64(cntBytes)) + 1 507 } 508 509 newCntBytes := make([]byte, 8) 510 binary.BigEndian.PutUint64(newCntBytes, uint64(cnt)) 511 ec.DposContext.MintCntTrie().TryUpdate(validator.Bytes(), newCntBytes) 512 } 513 514 func (ec *Snapshot) tryElect(genesis, parent *types.Header) error { 515 516 // if prevEpoch is not genesis, kickout not active candidate 517 /*if parent.Number.Uint64() != 0 { 518 if err := ec.kickoutValidator(); err != nil { 519 return err 520 } 521 }*/ 522 523 votes, err := ec.countVotes() 524 if err != nil { 525 return err 526 } 527 528 err = ec.CommitScores(votes) 529 if err != nil { 530 return err 531 } 532 533 candidates := types.SortableAddresses{} 534 for candidate, cnt := range votes { 535 candidates = append(candidates, &types.SortableAddress{Address: candidate, Weight: cnt}) 536 } 537 if len(candidates) < safeSize { 538 return errors.New("too few candidates") 539 } 540 sort.Sort(candidates) 541 if len(candidates) > maxValidatorSize { 542 candidates = candidates[:maxValidatorSize] 543 } 544 545 sortedValidators := make([]common.Address, 0) 546 for _, candidate := range candidates { 547 sortedValidators = append(sortedValidators, candidate.Address) 548 } 549 550 epochTrie, _ := types.NewEpochTrie(common.Hash{}, ec.DposContext.DB()) 551 ec.DposContext.SetEpoch(epochTrie) 552 ec.DposContext.SetValidators(sortedValidators) 553 ec.DposContext.SetSortableAddresses(candidates) 554 555 return nil 556 }