github.com/ImPedro29/bor@v0.2.7/consensus/bor/snapshot.go (about)

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