github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/bft/backend/snapshot.go (about)

     1  package backend
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  
     7  	"github.com/quickchainproject/quickchain/common"
     8  	"github.com/quickchainproject/quickchain/consensus/bft"
     9  	"github.com/quickchainproject/quickchain/consensus/bft/validator"
    10  	"github.com/quickchainproject/quickchain/core/types"
    11  	"github.com/quickchainproject/quickchain/qctdb"
    12  )
    13  
    14  const (
    15  	dbKeySnapshotPrefix = "bft-snapshot"
    16  )
    17  
    18  // Vote represents a single vote that an authorized validator made to modify the
    19  // list of authorizations.
    20  type Vote struct {
    21  	Validator common.Address `json:"validator"` // Authorized validator that cast this vote
    22  	Block     uint64         `json:"block"`     // Block number the vote was cast in (expire old votes)
    23  	Address   common.Address `json:"address"`   // Account being voted on to change its authorization
    24  	Authorize bool           `json:"authorize"` // Whether to authorize or deauthorize the voted account
    25  }
    26  
    27  // Tally is a simple vote tally to keep the current score of votes. Votes that
    28  // go against the proposal aren't counted since it's equivalent to not voting.
    29  type Tally struct {
    30  	Authorize bool `json:"authorize"` // Whether the vote it about authorizing or kicking someone
    31  	Votes     int  `json:"votes"`     // Number of votes until now wanting to pass the proposal
    32  }
    33  
    34  // Snapshot is the state of the authorization voting at a given point in time.
    35  type Snapshot struct {
    36  	Epoch uint64 // The number of blocks after which to checkpoint and reset the pending votes
    37  
    38  	Number uint64                   // Block number where the snapshot was created
    39  	Hash   common.Hash              // Block hash where the snapshot was created
    40  	Votes  []*Vote                  // List of votes cast in chronological order
    41  	Tally  map[common.Address]Tally // Current vote tally to avoid recalculating
    42  	ValSet bft.ValidatorSet    // Set of authorized validators at this moment
    43  }
    44  
    45  // newSnapshot create a new snapshot with the specified startup parameters. This
    46  // method does not initialize the set of recent validators, so only ever use if for
    47  // the genesis block.
    48  func newSnapshot(epoch uint64, number uint64, hash common.Hash, valSet bft.ValidatorSet) *Snapshot {
    49  	snap := &Snapshot{
    50  		Epoch:  epoch,
    51  		Number: number,
    52  		Hash:   hash,
    53  		ValSet: valSet,
    54  		Tally:  make(map[common.Address]Tally),
    55  	}
    56  	return snap
    57  }
    58  
    59  // loadSnapshot loads an existing snapshot from the database.
    60  func loadSnapshot(epoch uint64, db qctdb.Database, hash common.Hash) (*Snapshot, error) {
    61  	blob, err := db.Get(append([]byte(dbKeySnapshotPrefix), hash[:]...))
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	snap := new(Snapshot)
    66  	if err := json.Unmarshal(blob, snap); err != nil {
    67  		return nil, err
    68  	}
    69  	snap.Epoch = epoch
    70  
    71  	return snap, nil
    72  }
    73  
    74  // store inserts the snapshot into the database.
    75  func (s *Snapshot) store(db qctdb.Database) error {
    76  	blob, err := json.Marshal(s)
    77  	if err != nil {
    78  		return err
    79  	}
    80  	return db.Put(append([]byte(dbKeySnapshotPrefix), s.Hash[:]...), blob)
    81  }
    82  
    83  // copy creates a deep copy of the snapshot, though not the individual votes.
    84  func (s *Snapshot) copy() *Snapshot {
    85  	cpy := &Snapshot{
    86  		Epoch:  s.Epoch,
    87  		Number: s.Number,
    88  		Hash:   s.Hash,
    89  		ValSet: s.ValSet.Copy(),
    90  		Votes:  make([]*Vote, len(s.Votes)),
    91  		Tally:  make(map[common.Address]Tally),
    92  	}
    93  
    94  	for address, tally := range s.Tally {
    95  		cpy.Tally[address] = tally
    96  	}
    97  	copy(cpy.Votes, s.Votes)
    98  
    99  	return cpy
   100  }
   101  
   102  // checkVote return whether it's a valid vote
   103  func (s *Snapshot) checkVote(address common.Address, authorize bool) bool {
   104  	_, validator := s.ValSet.GetByAddress(address)
   105  	return (validator != nil && !authorize) || (validator == nil && authorize)
   106  }
   107  
   108  // cast adds a new vote into the tally.
   109  func (s *Snapshot) cast(address common.Address, authorize bool) bool {
   110  	// Ensure the vote is meaningful
   111  	if !s.checkVote(address, authorize) {
   112  		return false
   113  	}
   114  	// Cast the vote into an existing or new tally
   115  	if old, ok := s.Tally[address]; ok {
   116  		old.Votes++
   117  		s.Tally[address] = old
   118  	} else {
   119  		s.Tally[address] = Tally{Authorize: authorize, Votes: 1}
   120  	}
   121  	return true
   122  }
   123  
   124  // uncast removes a previously cast vote from the tally.
   125  func (s *Snapshot) uncast(address common.Address, authorize bool) bool {
   126  	// If there's no tally, it's a dangling vote, just drop
   127  	tally, ok := s.Tally[address]
   128  	if !ok {
   129  		return false
   130  	}
   131  	// Ensure we only revert counted votes
   132  	if tally.Authorize != authorize {
   133  		return false
   134  	}
   135  	// Otherwise revert the vote
   136  	if tally.Votes > 1 {
   137  		tally.Votes--
   138  		s.Tally[address] = tally
   139  	} else {
   140  		delete(s.Tally, address)
   141  	}
   142  	return true
   143  }
   144  
   145  // apply creates a new authorization snapshot by applying the given headers to
   146  // the original one.
   147  func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
   148  	// Allow passing in no headers for cleaner code
   149  	if len(headers) == 0 {
   150  		return s, nil
   151  	}
   152  	// Sanity check that the headers can be applied
   153  	for i := 0; i < len(headers)-1; i++ {
   154  		if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 {
   155  			return nil, errInvalidVotingChain
   156  		}
   157  	}
   158  	if headers[0].Number.Uint64() != s.Number+1 {
   159  		return nil, errInvalidVotingChain
   160  	}
   161  	// Iterate through the headers and create a new snapshot
   162  	snap := s.copy()
   163  
   164  	for _, header := range headers {
   165  		// Remove any votes on checkpoint blocks
   166  		number := header.Number.Uint64()
   167  		if number%s.Epoch == 0 {
   168  			snap.Votes = nil
   169  			snap.Tally = make(map[common.Address]Tally)
   170  		}
   171  		// Resolve the authorization key and check against validators
   172  		validator, err := ecrecover(header)
   173  		if err != nil {
   174  			return nil, err
   175  		}
   176  		if _, v := snap.ValSet.GetByAddress(validator); v == nil {
   177  			return nil, errUnauthorized
   178  		}
   179  
   180  		// Header authorized, discard any previous votes from the validator
   181  		for i, vote := range snap.Votes {
   182  			if vote.Validator == validator && vote.Address == header.Coinbase {
   183  				// Uncast the vote from the cached tally
   184  				snap.uncast(vote.Address, vote.Authorize)
   185  
   186  				// Uncast the vote from the chronological list
   187  				snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
   188  				break // only one vote allowed
   189  			}
   190  		}
   191  		// Tally up the new vote from the validator
   192  		var authorize bool
   193  		switch {
   194  		case bytes.Compare(header.Nonce[:], nonceAuthVote) == 0:
   195  			authorize = true
   196  		case bytes.Compare(header.Nonce[:], nonceDropVote) == 0:
   197  			authorize = false
   198  		default:
   199  			return nil, errInvalidVote
   200  		}
   201  		if snap.cast(header.Coinbase, authorize) {
   202  			snap.Votes = append(snap.Votes, &Vote{
   203  				Validator: validator,
   204  				Block:     number,
   205  				Address:   header.Coinbase,
   206  				Authorize: authorize,
   207  			})
   208  		}
   209  		// If the vote passed, update the list of validators
   210  		if tally := snap.Tally[header.Coinbase]; tally.Votes > snap.ValSet.Size()/2 {
   211  			if tally.Authorize {
   212  				snap.ValSet.AddValidator(header.Coinbase)
   213  			} else {
   214  				snap.ValSet.RemoveValidator(header.Coinbase)
   215  
   216  				// Discard any previous votes the deauthorized validator cast
   217  				for i := 0; i < len(snap.Votes); i++ {
   218  					if snap.Votes[i].Validator == header.Coinbase {
   219  						// Uncast the vote from the cached tally
   220  						snap.uncast(snap.Votes[i].Address, snap.Votes[i].Authorize)
   221  
   222  						// Uncast the vote from the chronological list
   223  						snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
   224  
   225  						i--
   226  					}
   227  				}
   228  			}
   229  			// Discard any previous votes around the just changed account
   230  			for i := 0; i < len(snap.Votes); i++ {
   231  				if snap.Votes[i].Address == header.Coinbase {
   232  					snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
   233  					i--
   234  				}
   235  			}
   236  			delete(snap.Tally, header.Coinbase)
   237  		}
   238  	}
   239  	snap.Number += uint64(len(headers))
   240  	snap.Hash = headers[len(headers)-1].Hash()
   241  
   242  	return snap, nil
   243  }
   244  
   245  // validators retrieves the list of authorized validators in ascending order.
   246  func (s *Snapshot) validators() []common.Address {
   247  	validators := make([]common.Address, 0, s.ValSet.Size())
   248  	for _, validator := range s.ValSet.List() {
   249  		validators = append(validators, validator.Address())
   250  	}
   251  	for i := 0; i < len(validators); i++ {
   252  		for j := i + 1; j < len(validators); j++ {
   253  			if bytes.Compare(validators[i][:], validators[j][:]) > 0 {
   254  				validators[i], validators[j] = validators[j], validators[i]
   255  			}
   256  		}
   257  	}
   258  	return validators
   259  }
   260  
   261  type snapshotJSON struct {
   262  	Epoch  uint64                   `json:"epoch"`
   263  	Number uint64                   `json:"number"`
   264  	Hash   common.Hash              `json:"hash"`
   265  	Votes  []*Vote                  `json:"votes"`
   266  	Tally  map[common.Address]Tally `json:"tally"`
   267  
   268  	// for validator set
   269  	Validators []common.Address        `json:"validators"`
   270  	Policy     bft.ProposerPolicy `json:"policy"`
   271  }
   272  
   273  func (s *Snapshot) toJSONStruct() *snapshotJSON {
   274  	return &snapshotJSON{
   275  		Epoch:      s.Epoch,
   276  		Number:     s.Number,
   277  		Hash:       s.Hash,
   278  		Votes:      s.Votes,
   279  		Tally:      s.Tally,
   280  		Validators: s.validators(),
   281  		Policy:     s.ValSet.Policy(),
   282  	}
   283  }
   284  
   285  // Unmarshal from a json byte array
   286  func (s *Snapshot) UnmarshalJSON(b []byte) error {
   287  	var j snapshotJSON
   288  	if err := json.Unmarshal(b, &j); err != nil {
   289  		return err
   290  	}
   291  
   292  	s.Epoch = j.Epoch
   293  	s.Number = j.Number
   294  	s.Hash = j.Hash
   295  	s.Votes = j.Votes
   296  	s.Tally = j.Tally
   297  	s.ValSet = validator.NewSet(j.Validators, j.Policy)
   298  	return nil
   299  }
   300  
   301  // Marshal to a json byte array
   302  func (s *Snapshot) MarshalJSON() ([]byte, error) {
   303  	j := s.toJSONStruct()
   304  	return json.Marshal(j)
   305  }