github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/consensus/bor/snapshot.go (about)

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