github.com/gilgames000/kcc-geth@v1.0.6/consensus/posa/snapshot.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package posa
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"sort"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/consensus"
    26  	"github.com/ethereum/go-ethereum/core/types"
    27  	"github.com/ethereum/go-ethereum/ethdb"
    28  	"github.com/ethereum/go-ethereum/params"
    29  	lru "github.com/hashicorp/golang-lru"
    30  )
    31  
    32  // Snapshot is the state of the authorization voting at a given point in time.
    33  type Snapshot struct {
    34  	config   *params.POSAConfig // Consensus engine parameters to fine tune behavior
    35  	sigcache *lru.ARCCache      // Cache of recent block signatures to speed up ecrecover
    36  
    37  	Number     uint64                      `json:"number"`     // Block number where the snapshot was created
    38  	Hash       common.Hash                 `json:"hash"`       // Block hash where the snapshot was created
    39  	Validators map[common.Address]struct{} `json:"validators"` // Set of authorized validators at this moment
    40  	Recents    map[uint64]common.Address   `json:"recents"`    // Set of recent validators for spam protections
    41  }
    42  
    43  // validatorsAscending implements the sort interface to allow sorting a list of addresses
    44  type validatorsAscending []common.Address
    45  
    46  func (s validatorsAscending) Len() int           { return len(s) }
    47  func (s validatorsAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 }
    48  func (s validatorsAscending) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
    49  
    50  // newSnapshot creates a new snapshot with the specified startup parameters. This
    51  // method does not initialize the set of recent validators, so only ever use if for
    52  // the genesis block.
    53  func newSnapshot(config *params.POSAConfig, sigcache *lru.ARCCache, number uint64, hash common.Hash, validators []common.Address) *Snapshot {
    54  	snap := &Snapshot{
    55  		config:     config,
    56  		sigcache:   sigcache,
    57  		Number:     number,
    58  		Hash:       hash,
    59  		Validators: make(map[common.Address]struct{}),
    60  		Recents:    make(map[uint64]common.Address),
    61  	}
    62  	for _, validator := range validators {
    63  		snap.Validators[validator] = struct{}{}
    64  	}
    65  	return snap
    66  }
    67  
    68  // loadSnapshot loads an existing snapshot from the database.
    69  func loadSnapshot(config *params.POSAConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash) (*Snapshot, error) {
    70  	blob, err := db.Get(append([]byte("congress-"), hash[:]...))
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	snap := new(Snapshot)
    75  	if err := json.Unmarshal(blob, snap); err != nil {
    76  		return nil, err
    77  	}
    78  	snap.config = config
    79  	snap.sigcache = sigcache
    80  
    81  	return snap, nil
    82  }
    83  
    84  // store inserts the snapshot into the database.
    85  func (s *Snapshot) store(db ethdb.Database) error {
    86  	blob, err := json.Marshal(s)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	return db.Put(append([]byte("congress-"), s.Hash[:]...), blob)
    91  }
    92  
    93  // copy creates a deep copy of the snapshot, though not the individual votes.
    94  func (s *Snapshot) copy() *Snapshot {
    95  	cpy := &Snapshot{
    96  		config:     s.config,
    97  		sigcache:   s.sigcache,
    98  		Number:     s.Number,
    99  		Hash:       s.Hash,
   100  		Validators: make(map[common.Address]struct{}),
   101  		Recents:    make(map[uint64]common.Address),
   102  	}
   103  	for validator := range s.Validators {
   104  		cpy.Validators[validator] = struct{}{}
   105  	}
   106  	for block, validator := range s.Recents {
   107  		cpy.Recents[block] = validator
   108  	}
   109  
   110  	return cpy
   111  }
   112  
   113  // apply creates a new authorization snapshot by applying the given headers to
   114  // the original one.
   115  func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderReader, parents []*types.Header) (*Snapshot, error) {
   116  	// Allow passing in no headers for cleaner code
   117  	if len(headers) == 0 {
   118  		return s, nil
   119  	}
   120  	// Sanity check that the headers can be applied
   121  	for i := 0; i < len(headers)-1; i++ {
   122  		if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 {
   123  			return nil, errInvalidVotingChain
   124  		}
   125  	}
   126  	if headers[0].Number.Uint64() != s.Number+1 {
   127  		return nil, errInvalidVotingChain
   128  	}
   129  	// Iterate through the headers and create a new snapshot
   130  	snap := s.copy()
   131  
   132  	for _, header := range headers {
   133  		// Remove any votes on checkpoint blocks
   134  		number := header.Number.Uint64()
   135  		// Delete the oldest validator from the recent list to allow it signing again
   136  		if limit := uint64(len(snap.Validators)/2 + 1); number >= limit {
   137  			delete(snap.Recents, number-limit)
   138  		}
   139  		// Resolve the authorization key and check against validators
   140  		validator, err := ecrecover(header, s.sigcache)
   141  		if err != nil {
   142  			return nil, err
   143  		}
   144  		if _, ok := snap.Validators[validator]; !ok {
   145  			return nil, errUnauthorizedValidator
   146  		}
   147  		for _, recent := range snap.Recents {
   148  			if recent == validator {
   149  				return nil, errRecentlySigned
   150  			}
   151  		}
   152  		snap.Recents[number] = validator
   153  
   154  		// update validators at the first block at epoch
   155  		if number > 0 && number%s.config.Epoch == 0 {
   156  			checkpointHeader := header
   157  
   158  			// get validators from headers and use that for new validator set
   159  			validators := make([]common.Address, (len(checkpointHeader.Extra)-extraVanity-extraSeal)/common.AddressLength)
   160  			for i := 0; i < len(validators); i++ {
   161  				copy(validators[i][:], checkpointHeader.Extra[extraVanity+i*common.AddressLength:])
   162  			}
   163  
   164  			newValidators := make(map[common.Address]struct{})
   165  			for _, validator := range validators {
   166  				newValidators[validator] = struct{}{}
   167  			}
   168  
   169  			// need to delete recorded recent seen blocks if necessary, it may pause whole chain when validators length
   170  			// decreases.
   171  			limit := uint64(len(newValidators)/2 + 1)
   172  			for i := 0; i < len(snap.Validators)/2-len(newValidators)/2; i++ {
   173  				delete(snap.Recents, number-limit-uint64(i))
   174  			}
   175  
   176  			snap.Validators = newValidators
   177  		}
   178  	}
   179  
   180  	snap.Number += uint64(len(headers))
   181  	snap.Hash = headers[len(headers)-1].Hash()
   182  
   183  	return snap, nil
   184  }
   185  
   186  // validators retrieves the list of authorized validators in ascending order.
   187  func (s *Snapshot) validators() []common.Address {
   188  	sigs := make([]common.Address, 0, len(s.Validators))
   189  	for sig := range s.Validators {
   190  		sigs = append(sigs, sig)
   191  	}
   192  	sort.Sort(validatorsAscending(sigs))
   193  	return sigs
   194  }
   195  
   196  // inturn returns if a validator at a given block height is in-turn or not.
   197  func (s *Snapshot) inturn(number uint64, validator common.Address) bool {
   198  	validators, offset := s.validators(), 0
   199  	for offset < len(validators) && validators[offset] != validator {
   200  		offset++
   201  	}
   202  	return (number % uint64(len(validators))) == uint64(offset)
   203  }