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  }