gitlab.com/yannislg/go-pulse@v0.0.0-20210722055913-a3e24e95638d/consensus/parlia/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 parlia
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/hex"
    22  	"encoding/json"
    23  	"errors"
    24  	"math/big"
    25  	"sort"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/consensus"
    29  	"github.com/ethereum/go-ethereum/core/types"
    30  	"github.com/ethereum/go-ethereum/ethdb"
    31  	"github.com/ethereum/go-ethereum/internal/ethapi"
    32  	"github.com/ethereum/go-ethereum/log"
    33  	"github.com/ethereum/go-ethereum/params"
    34  	lru "github.com/hashicorp/golang-lru"
    35  )
    36  
    37  // Snapshot is the state of the validatorSet at a given point.
    38  type Snapshot struct {
    39  	config   *params.ParliaConfig // Consensus engine parameters to fine tune behavior
    40  	ethAPI   *ethapi.PublicBlockChainAPI
    41  	sigCache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover
    42  
    43  	Number           uint64                      `json:"number"`             // Block number where the snapshot was created
    44  	Hash             common.Hash                 `json:"hash"`               // Block hash where the snapshot was created
    45  	Validators       map[common.Address]struct{} `json:"validators"`         // Set of authorized validators at this moment
    46  	Recents          map[uint64]common.Address   `json:"recents"`            // Set of recent validators for spam protections
    47  	RecentForkHashes map[uint64]string           `json:"recent_fork_hashes"` // Set of recent forkHash
    48  }
    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 it for
    52  // the genesis block.
    53  func newSnapshot(
    54  	config *params.ParliaConfig,
    55  	sigCache *lru.ARCCache,
    56  	number uint64,
    57  	hash common.Hash,
    58  	validators []common.Address,
    59  	ethAPI *ethapi.PublicBlockChainAPI,
    60  ) *Snapshot {
    61  	snap := &Snapshot{
    62  		config:           config,
    63  		ethAPI:           ethAPI,
    64  		sigCache:         sigCache,
    65  		Number:           number,
    66  		Hash:             hash,
    67  		Recents:          make(map[uint64]common.Address),
    68  		RecentForkHashes: make(map[uint64]string),
    69  		Validators:       make(map[common.Address]struct{}),
    70  	}
    71  	for _, v := range validators {
    72  		snap.Validators[v] = struct{}{}
    73  	}
    74  	return snap
    75  }
    76  
    77  // validatorsAscending implements the sort interface to allow sorting a list of addresses
    78  type validatorsAscending []common.Address
    79  
    80  func (s validatorsAscending) Len() int           { return len(s) }
    81  func (s validatorsAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 }
    82  func (s validatorsAscending) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
    83  
    84  // loadSnapshot loads an existing snapshot from the database.
    85  func loadSnapshot(config *params.ParliaConfig, sigCache *lru.ARCCache, db ethdb.Database, hash common.Hash, ethAPI *ethapi.PublicBlockChainAPI) (*Snapshot, error) {
    86  	blob, err := db.Get(append([]byte("parlia-"), hash[:]...))
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	snap := new(Snapshot)
    91  	if err := json.Unmarshal(blob, snap); err != nil {
    92  		return nil, err
    93  	}
    94  	snap.config = config
    95  	snap.sigCache = sigCache
    96  	snap.ethAPI = ethAPI
    97  
    98  	return snap, nil
    99  }
   100  
   101  // store inserts the snapshot into the database.
   102  func (s *Snapshot) store(db ethdb.Database) error {
   103  	blob, err := json.Marshal(s)
   104  	if err != nil {
   105  		return err
   106  	}
   107  	return db.Put(append([]byte("parlia-"), s.Hash[:]...), blob)
   108  }
   109  
   110  // copy creates a deep copy of the snapshot
   111  func (s *Snapshot) copy() *Snapshot {
   112  	cpy := &Snapshot{
   113  		config:           s.config,
   114  		ethAPI:           s.ethAPI,
   115  		sigCache:         s.sigCache,
   116  		Number:           s.Number,
   117  		Hash:             s.Hash,
   118  		Validators:       make(map[common.Address]struct{}),
   119  		Recents:          make(map[uint64]common.Address),
   120  		RecentForkHashes: make(map[uint64]string),
   121  	}
   122  
   123  	for v := range s.Validators {
   124  		cpy.Validators[v] = struct{}{}
   125  	}
   126  	for block, v := range s.Recents {
   127  		cpy.Recents[block] = v
   128  	}
   129  	for block, id := range s.RecentForkHashes {
   130  		cpy.RecentForkHashes[block] = id
   131  	}
   132  	return cpy
   133  }
   134  
   135  func (s *Snapshot) isMajorityFork(forkHash string) bool {
   136  	ally := 0
   137  	for _, h := range s.RecentForkHashes {
   138  		if h == forkHash {
   139  			ally++
   140  		}
   141  	}
   142  	return ally > len(s.RecentForkHashes)/2
   143  }
   144  
   145  // apply creates a new authorization snapshot by applying the given headers to the original one
   146  func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainReader, parents []*types.Header, chainId *big.Int) (*Snapshot, error) {
   147  	// Allow passing in no headers for cleaner code
   148  	if len(headers) == 0 {
   149  		return s, nil
   150  	}
   151  	// Sanity check that the headers can be applied
   152  	for i := 0; i < len(headers)-1; i++ {
   153  		if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 {
   154  			return nil, errOutOfRangeChain
   155  		}
   156  		if !bytes.Equal(headers[i+1].ParentHash.Bytes(), headers[i].Hash().Bytes()) {
   157  			return nil, errBlockHashInconsistent
   158  		}
   159  	}
   160  	if headers[0].Number.Uint64() != s.Number+1 {
   161  		return nil, errOutOfRangeChain
   162  	}
   163  	if !bytes.Equal(headers[0].ParentHash.Bytes(), s.Hash.Bytes()) {
   164  		return nil, errBlockHashInconsistent
   165  	}
   166  	// Iterate through the headers and create a new snapshot
   167  	snap := s.copy()
   168  
   169  	for _, header := range headers {
   170  		number := header.Number.Uint64()
   171  		// Delete the oldest validator from the recent list to allow it signing again
   172  		if limit := uint64(len(snap.Validators)/2 + 1); number >= limit {
   173  			delete(snap.Recents, number-limit)
   174  		}
   175  		if limit := uint64(len(snap.Validators)); number >= limit {
   176  			delete(snap.RecentForkHashes, number-limit)
   177  		}
   178  		// Resolve the authorization key and check against signers
   179  		validator, err := ecrecover(header, s.sigCache, chainId)
   180  		if err != nil {
   181  			return nil, err
   182  		}
   183  		if _, ok := snap.Validators[validator]; !ok {
   184  			return nil, errUnauthorizedValidator
   185  		}
   186  		for _, recent := range snap.Recents {
   187  			if recent == validator {
   188  				return nil, errRecentlySigned
   189  			}
   190  		}
   191  		snap.Recents[number] = validator
   192  		// change validator set
   193  		offset := uint64(len(snap.Validators) / 2)
   194  		if number > 0 && number%s.config.Epoch == offset {
   195  			checkpointHeader := FindAncientHeader(header, offset, chain, parents)
   196  			if checkpointHeader == nil {
   197  				return nil, consensus.ErrUnknownAncestor
   198  			}
   199  			if len(checkpointHeader.Extra) >= extraVanity+extraSeal {
   200  				validatorBytes := checkpointHeader.Extra[extraVanity : len(checkpointHeader.Extra)-extraSeal]
   201  				// get validators from headers and use that for new validator set
   202  				newValArr, err := ParseValidators(validatorBytes)
   203  				if err != nil {
   204  					return nil, err
   205  				}
   206  				newVals := make(map[common.Address]struct{}, len(newValArr))
   207  				for _, val := range newValArr {
   208  					newVals[val] = struct{}{}
   209  				}
   210  				oldLimit := len(snap.Validators)/2 + 1
   211  				newLimit := len(newVals)/2 + 1
   212  				if newLimit < oldLimit {
   213  					for i := 0; i < oldLimit-newLimit; i++ {
   214  						delete(snap.Recents, number-uint64(newLimit)-uint64(i))
   215  					}
   216  				}
   217  				oldLimit = len(snap.Validators)
   218  				newLimit = len(newVals)
   219  				if newLimit < oldLimit {
   220  					for i := 0; i < oldLimit-newLimit; i++ {
   221  						delete(snap.RecentForkHashes, number-uint64(newLimit)-uint64(i))
   222  					}
   223  				}
   224  				snap.Validators = newVals
   225  			} else {
   226  				// this can potentially happen one time only for a new chain, if the most recent epoch block was pre-fork
   227  				// this entirely depends on which block number the fork occurs along with the parlia.epoch config
   228  				log.Warn("Skipping validator rotation: epoch header malformed", "number", number, "epoch", checkpointHeader.Number)
   229  			}
   230  		}
   231  		snap.RecentForkHashes[number] = hex.EncodeToString(header.Extra[extraVanity-nextForkHashSize : extraVanity])
   232  	}
   233  	snap.Number += uint64(len(headers))
   234  	snap.Hash = headers[len(headers)-1].Hash()
   235  	return snap, nil
   236  }
   237  
   238  // validators retrieves the list of validators in ascending order.
   239  func (s *Snapshot) validators() []common.Address {
   240  	validators := make([]common.Address, 0, len(s.Validators))
   241  	for v := range s.Validators {
   242  		validators = append(validators, v)
   243  	}
   244  	sort.Sort(validatorsAscending(validators))
   245  	return validators
   246  }
   247  
   248  // inturn returns if a validator at a given block height is in-turn or not.
   249  func (s *Snapshot) inturn(validator common.Address) bool {
   250  	validators := s.validators()
   251  	offset := (s.Number + 1) % uint64(len(validators))
   252  	return validators[offset] == validator
   253  }
   254  
   255  func (s *Snapshot) indexOfVal(validator common.Address) int {
   256  	validators := s.validators()
   257  	for idx, val := range validators {
   258  		if val == validator {
   259  			return idx
   260  		}
   261  	}
   262  	return -1
   263  }
   264  
   265  func (s *Snapshot) supposeValidator() common.Address {
   266  	validators := s.validators()
   267  	index := (s.Number + 1) % uint64(len(validators))
   268  	return validators[index]
   269  }
   270  
   271  func ParseValidators(validatorsBytes []byte) ([]common.Address, error) {
   272  	if len(validatorsBytes)%validatorBytesLength != 0 {
   273  		return nil, errors.New("invalid validators bytes")
   274  	}
   275  	n := len(validatorsBytes) / validatorBytesLength
   276  	result := make([]common.Address, n)
   277  	for i := 0; i < n; i++ {
   278  		address := make([]byte, validatorBytesLength)
   279  		copy(address, validatorsBytes[i*validatorBytesLength:(i+1)*validatorBytesLength])
   280  		result[i] = common.BytesToAddress(address)
   281  	}
   282  	return result, nil
   283  }
   284  
   285  func FindAncientHeader(header *types.Header, ite uint64, chain consensus.ChainReader, candidateParents []*types.Header) *types.Header {
   286  	ancient := header
   287  	for i := uint64(1); i <= ite; i++ {
   288  		parentHash := ancient.ParentHash
   289  		parentHeight := ancient.Number.Uint64() - 1
   290  		found := false
   291  		if len(candidateParents) > 0 {
   292  			index := sort.Search(len(candidateParents), func(i int) bool {
   293  				return candidateParents[i].Number.Uint64() >= parentHeight
   294  			})
   295  			if index < len(candidateParents) && candidateParents[index].Number.Uint64() == parentHeight &&
   296  				candidateParents[index].Hash() == parentHash {
   297  				ancient = candidateParents[index]
   298  				found = true
   299  			}
   300  		}
   301  		if !found {
   302  			ancient = chain.GetHeader(parentHash, parentHeight)
   303  			found = true
   304  		}
   305  		if ancient == nil || !found {
   306  			return nil
   307  		}
   308  	}
   309  	return ancient
   310  }