github.com/bloxroute-labs/bor@v0.1.4/consensus/bor/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 bor
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  
    23  	lru "github.com/hashicorp/golang-lru"
    24  
    25  	"github.com/maticnetwork/bor/common"
    26  	"github.com/maticnetwork/bor/core/types"
    27  	"github.com/maticnetwork/bor/ethdb"
    28  	"github.com/maticnetwork/bor/internal/ethapi"
    29  	"github.com/maticnetwork/bor/log"
    30  	"github.com/maticnetwork/bor/params"
    31  )
    32  
    33  // Snapshot is the state of the authorization voting at a given point in time.
    34  type Snapshot struct {
    35  	config   *params.BorConfig // Consensus engine parameters to fine tune behavior
    36  	ethAPI   *ethapi.PublicBlockChainAPI
    37  	sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover
    38  
    39  	Number       uint64                    `json:"number"`       // Block number where the snapshot was created
    40  	Hash         common.Hash               `json:"hash"`         // Block hash where the snapshot was created
    41  	ValidatorSet *ValidatorSet             `json:"validatorSet"` // Validator set at this moment
    42  	Recents      map[uint64]common.Address `json:"recents"`      // Set of recent signers for spam protections
    43  }
    44  
    45  // signersAscending implements the sort interface to allow sorting a list of addresses
    46  type signersAscending []common.Address
    47  
    48  func (s signersAscending) Len() int           { return len(s) }
    49  func (s signersAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 }
    50  func (s signersAscending) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
    51  
    52  // newSnapshot creates a new snapshot with the specified startup parameters. This
    53  // method does not initialize the set of recent signers, so only ever use if for
    54  // the genesis block.
    55  func newSnapshot(
    56  	config *params.BorConfig,
    57  	sigcache *lru.ARCCache,
    58  	number uint64,
    59  	hash common.Hash,
    60  	validators []*Validator,
    61  	ethAPI *ethapi.PublicBlockChainAPI,
    62  ) *Snapshot {
    63  	snap := &Snapshot{
    64  		config:       config,
    65  		ethAPI:       ethAPI,
    66  		sigcache:     sigcache,
    67  		Number:       number,
    68  		Hash:         hash,
    69  		ValidatorSet: NewValidatorSet(validators),
    70  		Recents:      make(map[uint64]common.Address),
    71  	}
    72  	return snap
    73  }
    74  
    75  // loadSnapshot loads an existing snapshot from the database.
    76  func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash, ethAPI *ethapi.PublicBlockChainAPI) (*Snapshot, error) {
    77  	blob, err := db.Get(append([]byte("bor-"), hash[:]...))
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	snap := new(Snapshot)
    82  	if err := json.Unmarshal(blob, snap); err != nil {
    83  		return nil, err
    84  	}
    85  	snap.config = config
    86  	snap.sigcache = sigcache
    87  	snap.ethAPI = ethAPI
    88  
    89  	// update total voting power
    90  	snap.ValidatorSet.updateTotalVotingPower()
    91  
    92  	return snap, nil
    93  }
    94  
    95  // store inserts the snapshot into the database.
    96  func (s *Snapshot) store(db ethdb.Database) error {
    97  	blob, err := json.Marshal(s)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	return db.Put(append([]byte("bor-"), s.Hash[:]...), blob)
   102  }
   103  
   104  // copy creates a deep copy of the snapshot, though not the individual votes.
   105  func (s *Snapshot) copy() *Snapshot {
   106  	cpy := &Snapshot{
   107  		config:       s.config,
   108  		ethAPI:       s.ethAPI,
   109  		sigcache:     s.sigcache,
   110  		Number:       s.Number,
   111  		Hash:         s.Hash,
   112  		ValidatorSet: s.ValidatorSet.Copy(),
   113  		Recents:      make(map[uint64]common.Address),
   114  	}
   115  	for block, signer := range s.Recents {
   116  		cpy.Recents[block] = signer
   117  	}
   118  
   119  	return cpy
   120  }
   121  
   122  func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
   123  	// Allow passing in no headers for cleaner code
   124  	if len(headers) == 0 {
   125  		return s, nil
   126  	}
   127  	// Sanity check that the headers can be applied
   128  	for i := 0; i < len(headers)-1; i++ {
   129  		if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 {
   130  			return nil, errOutOfRangeChain
   131  		}
   132  	}
   133  	if headers[0].Number.Uint64() != s.Number+1 {
   134  		return nil, errOutOfRangeChain
   135  	}
   136  	// Iterate through the headers and create a new snapshot
   137  	snap := s.copy()
   138  
   139  	for _, header := range headers {
   140  		// Remove any votes on checkpoint blocks
   141  		number := header.Number.Uint64()
   142  
   143  		// Delete the oldest signer from the recent list to allow it signing again
   144  		if number >= s.config.Sprint && number-s.config.Sprint >= 0 {
   145  			delete(snap.Recents, number-s.config.Sprint)
   146  		}
   147  
   148  		// Resolve the authorization key and check against signers
   149  		signer, err := ecrecover(header, s.sigcache)
   150  		if err != nil {
   151  			return nil, err
   152  		}
   153  
   154  		// check if signer is in validator set
   155  		if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
   156  			return nil, errUnauthorizedSigner
   157  		}
   158  
   159  		//
   160  		// Check validator
   161  		//
   162  
   163  		validators := snap.ValidatorSet.Validators
   164  		// proposer will be the last signer if block is not epoch block
   165  		proposer := snap.ValidatorSet.GetProposer().Address
   166  		proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer)
   167  		signerIndex, _ := snap.ValidatorSet.GetByAddress(signer)
   168  		limit := len(validators)/2 + 1
   169  
   170  		// temp index
   171  		tempIndex := signerIndex
   172  		if proposerIndex != tempIndex && limit > 0 {
   173  			if tempIndex < proposerIndex {
   174  				tempIndex = tempIndex + len(validators)
   175  			}
   176  
   177  			if tempIndex-proposerIndex > limit {
   178  				log.Info("Invalid signer: error while applying headers", "proposerIndex", validators[proposerIndex].Address.Hex(), "signerIndex", validators[signerIndex].Address.Hex())
   179  				return nil, errRecentlySigned
   180  			}
   181  		}
   182  
   183  		// add recents
   184  		snap.Recents[number] = signer
   185  
   186  		// change validator set and change proposer
   187  		if number > 0 && (number+1)%s.config.Sprint == 0 {
   188  			validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal]
   189  
   190  			// get validators from headers and use that for new validator set
   191  			newVals, _ := ParseValidators(validatorBytes)
   192  			v := getUpdatedValidatorSet(snap.ValidatorSet.Copy(), newVals)
   193  			v.IncrementProposerPriority(1)
   194  			snap.ValidatorSet = v
   195  		}
   196  	}
   197  	snap.Number += uint64(len(headers))
   198  	snap.Hash = headers[len(headers)-1].Hash()
   199  
   200  	return snap, nil
   201  }
   202  
   203  // signers retrieves the list of authorized signers in ascending order.
   204  func (s *Snapshot) signers() []common.Address {
   205  	sigs := make([]common.Address, 0, len(s.ValidatorSet.Validators))
   206  	for _, sig := range s.ValidatorSet.Validators {
   207  		sigs = append(sigs, sig.Address)
   208  	}
   209  	return sigs
   210  }
   211  
   212  // inturn returns if a signer at a given block height is in-turn or not.
   213  func (s *Snapshot) inturn(number uint64, signer common.Address, epoch uint64) uint64 {
   214  	// if signer is empty
   215  	if bytes.Compare(signer.Bytes(), common.Address{}.Bytes()) == 0 {
   216  		return 1
   217  	}
   218  
   219  	validators := s.ValidatorSet.Validators
   220  	proposer := s.ValidatorSet.GetProposer().Address
   221  	totalValidators := len(validators)
   222  
   223  	proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer)
   224  	signerIndex, _ := s.ValidatorSet.GetByAddress(signer)
   225  
   226  	// temp index
   227  	tempIndex := signerIndex
   228  	if tempIndex < proposerIndex {
   229  		tempIndex = tempIndex + totalValidators
   230  	}
   231  
   232  	return uint64(totalValidators - (tempIndex - proposerIndex))
   233  }