github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/consensus/istanbul/backend/engine.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 backend
    18  
    19  import (
    20  	"math/big"
    21  	"math/rand"
    22  	"time"
    23  
    24  	"github.com/electroneum/electroneum-sc/common"
    25  	"github.com/electroneum/electroneum-sc/common/math"
    26  	"github.com/electroneum/electroneum-sc/consensus"
    27  	"github.com/electroneum/electroneum-sc/consensus/istanbul"
    28  	istanbulcommon "github.com/electroneum/electroneum-sc/consensus/istanbul/common"
    29  	"github.com/electroneum/electroneum-sc/consensus/istanbul/validator"
    30  	"github.com/electroneum/electroneum-sc/core/state"
    31  	"github.com/electroneum/electroneum-sc/core/types"
    32  	"github.com/electroneum/electroneum-sc/ethdb"
    33  	"github.com/electroneum/electroneum-sc/log"
    34  	"github.com/electroneum/electroneum-sc/params"
    35  	"github.com/electroneum/electroneum-sc/rpc"
    36  )
    37  
    38  const (
    39  	checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database
    40  	inmemorySnapshots  = 128  // Number of recent vote snapshots to keep in memory
    41  	inmemoryEmissions  = 128
    42  	inmemoryPeers      = 40
    43  	inmemoryMessages   = 1024
    44  )
    45  
    46  // Author retrieves the Ethereum address of the account that minted the given
    47  // block, which may be different from the header's coinbase if a consensus
    48  // engine is based on signatures.
    49  func (sb *Backend) Author(header *types.Header) (common.Address, error) {
    50  	return sb.EngineForBlockNumber(header.Number).Author(header)
    51  }
    52  
    53  // Signers extracts all the addresses who have signed the given header
    54  // It will extract for each seal who signed it, regardless of if the seal is
    55  // repeated
    56  func (sb *Backend) Signers(header *types.Header) ([]common.Address, error) {
    57  	return sb.EngineForBlockNumber(header.Number).Signers(header)
    58  }
    59  
    60  // VerifyHeader checks whether a header conforms to the consensus rules of a
    61  // given engine. Verifying the seal may be done optionally here, or explicitly
    62  // via the VerifySeal method.
    63  func (sb *Backend) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error {
    64  	return sb.verifyHeader(chain, header, nil)
    65  }
    66  
    67  func (sb *Backend) verifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) error {
    68  	// Assemble the voting snapshot
    69  	snap, err := sb.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, parents)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	// Compute etn emission per block
    75  	_, err = sb.emission(chain, header.Number.Uint64()-1, header.ParentHash, parents)
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	return sb.EngineForBlockNumber(header.Number).VerifyHeader(chain, header, parents, snap.ValSet)
    81  }
    82  
    83  // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
    84  // concurrently. The method returns a quit channel to abort the operations and
    85  // a results channel to retrieve the async verifications (the order is that of
    86  // the input slice).
    87  func (sb *Backend) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
    88  	abort := make(chan struct{})
    89  	results := make(chan error, len(headers))
    90  	go func() {
    91  		errored := false
    92  		for i, header := range headers {
    93  			var err error
    94  			if errored {
    95  				err = consensus.ErrUnknownAncestor
    96  			} else {
    97  				err = sb.verifyHeader(chain, header, headers[:i])
    98  			}
    99  
   100  			if err != nil {
   101  				errored = true
   102  			}
   103  
   104  			select {
   105  			case <-abort:
   106  				return
   107  			case results <- err:
   108  			}
   109  		}
   110  	}()
   111  	return abort, results
   112  }
   113  
   114  // VerifyUncles verifies that the given block's uncles conform to the consensus
   115  // rules of a given engine.
   116  func (sb *Backend) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
   117  	return sb.EngineForBlockNumber(block.Header().Number).VerifyUncles(chain, block)
   118  }
   119  
   120  // VerifySeal checks whether the crypto seal on a header is valid according to
   121  // the consensus rules of the given engine.
   122  func (sb *Backend) VerifySeal(chain consensus.ChainHeaderReader, header *types.Header) error {
   123  	// get parent header and ensure the signer is in parent's validator set
   124  	number := header.Number.Uint64()
   125  	if number == 0 {
   126  		return istanbulcommon.ErrUnknownBlock
   127  	}
   128  
   129  	// Assemble the voting snapshot
   130  	snap, err := sb.snapshot(chain, number-1, header.ParentHash, nil)
   131  	if err != nil {
   132  		return err
   133  	}
   134  
   135  	return sb.EngineForBlockNumber(header.Number).VerifySeal(chain, header, snap.ValSet)
   136  }
   137  
   138  // Prepare initializes the consensus fields of a block header according to the
   139  // rules of a particular engine. The changes are executed inline.
   140  func (sb *Backend) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
   141  	// Assemble the voting snapshot
   142  	snap, err := sb.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, nil)
   143  	if err != nil {
   144  		return err
   145  	}
   146  
   147  	err = sb.EngineForBlockNumber(header.Number).Prepare(chain, header, snap.ValSet)
   148  	if err != nil {
   149  		return err
   150  	}
   151  
   152  	// get valid candidate list
   153  	sb.candidatesLock.RLock()
   154  	var addresses []common.Address
   155  	var authorizes []bool
   156  	for address, authorize := range sb.candidates {
   157  		if snap.checkVote(address, authorize) {
   158  			addresses = append(addresses, address)
   159  			authorizes = append(authorizes, authorize)
   160  		}
   161  	}
   162  	sb.candidatesLock.RUnlock()
   163  
   164  	if len(addresses) > 0 {
   165  		index := rand.Intn(len(addresses))
   166  
   167  		err = sb.EngineForBlockNumber(header.Number).WriteVote(header, addresses[index], authorizes[index])
   168  		if err != nil {
   169  			log.Error("IBFT: error writing validator vote", "err", err)
   170  			return err
   171  		}
   172  	}
   173  
   174  	return nil
   175  }
   176  
   177  // Finalize runs any post-transaction state modifications (e.g. block rewards)
   178  // and assembles the final block.
   179  //
   180  // Note, the block header and state database might be updated to reflect any
   181  // consensus rules that happen at finalization (e.g. block rewards).
   182  func (sb *Backend) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {
   183  	if header.Coinbase != (common.Address{}) {
   184  		blockReward := sb.GetBaseBlockReward(chain, header)
   185  		state.AddBalance(header.Coinbase, blockReward)
   186  	}
   187  	sb.EngineForBlockNumber(header.Number).Finalize(chain, header, state, txs, uncles)
   188  }
   189  
   190  // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
   191  // nor block rewards given, and returns the final block.
   192  func (sb *Backend) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
   193  	sb.Finalize(chain, header, state, txs, uncles)
   194  	return sb.EngineForBlockNumber(header.Number).FinalizeAndAssemble(chain, header, state, txs, uncles, receipts)
   195  }
   196  
   197  // Seal generates a new block for the given input block with the local miner's
   198  // seal place on top.
   199  func (sb *Backend) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
   200  	// update the block header timestamp and signature and propose the block to core engine
   201  	header := block.Header()
   202  	number := header.Number.Uint64()
   203  
   204  	// Bail out if we're unauthorized to sign a block
   205  	snap, err := sb.snapshot(chain, number-1, header.ParentHash, nil)
   206  	if err != nil {
   207  		return err
   208  	}
   209  
   210  	block, err = sb.EngineForBlockNumber(header.Number).Seal(chain, block, snap.ValSet)
   211  	if err != nil {
   212  		return err
   213  	}
   214  
   215  	delay := time.Until(time.Unix(int64(block.Header().Time), 0))
   216  
   217  	go func() {
   218  		// wait for the timestamp of header, use this to adjust the block period
   219  		select {
   220  		case <-time.After(delay):
   221  		case <-stop:
   222  			results <- nil
   223  			return
   224  		}
   225  
   226  		// get the proposed block hash and clear it if the seal() is completed.
   227  		sb.sealMu.Lock()
   228  		sb.proposedBlockHash = block.Hash()
   229  
   230  		defer func() {
   231  			sb.proposedBlockHash = common.Hash{}
   232  			sb.sealMu.Unlock()
   233  		}()
   234  		// post block into Istanbul engine
   235  		go sb.EventMux().Post(istanbul.RequestEvent{
   236  			Proposal: block,
   237  		})
   238  		for {
   239  			select {
   240  			case result := <-sb.commitCh:
   241  				// if the block hash and the hash from channel are the same,
   242  				// return the result. Otherwise, keep waiting the next hash.
   243  				if result != nil && block.Hash() == result.Hash() {
   244  					results <- result
   245  					return
   246  				}
   247  			case <-stop:
   248  				results <- nil
   249  				return
   250  			}
   251  		}
   252  	}()
   253  	return nil
   254  }
   255  
   256  func (sb *Backend) GetBaseBlockReward(chain consensus.ChainHeaderReader, header *types.Header) *big.Int {
   257  	var legacyV9BlockHeight = big.NewInt(862866 * 24) // original 862866 height * 24 to make it compatible with 5-second block time
   258  	var halvingPeriod = big.NewInt(25228800)          // 4 years in 5-second block time
   259  	var baseReward = big.NewInt(4e+18)                // ~100ETN every 120 seconds
   260  
   261  	var offset = new(big.Int).Sub(big.NewInt(1500000*24), legacyV9BlockHeight) // block height at time of BC migration - legacyV9BlockHeight
   262  
   263  	var offsetBlockNumber = new(big.Int).Add(header.Number, offset)
   264  	var halvings = new(big.Int).Div(offsetBlockNumber, halvingPeriod) // (blockNumber + offset) / halvingPeriod
   265  
   266  	// Get current circulating supply
   267  	emission, err := sb.emission(chain, header.Number.Uint64()-1, header.ParentHash, nil)
   268  	if err != nil {
   269  		return big.NewInt(0)
   270  	}
   271  
   272  	// 0 block reward once circulating supply = max supply
   273  	if emission.CirculatingSupply.Cmp(math.MustParseBig256(params.ETNMaxSupply)) >= 0 {
   274  		return big.NewInt(0)
   275  	}
   276  
   277  	// Shift the base reward "halvings" times
   278  	return new(big.Int).Rsh(baseReward, uint(halvings.Uint64()))
   279  }
   280  
   281  func (sb *Backend) GetTotalEmission(chain consensus.ChainHeaderReader, header *types.Header) *big.Int {
   282  	emission, err := sb.emission(chain, header.Number.Uint64()-1, header.ParentHash, nil)
   283  	if err != nil {
   284  		return big.NewInt(0)
   285  	}
   286  	return emission.CirculatingSupply
   287  }
   288  
   289  // APIs returns the RPC APIs this consensus engine provides.
   290  func (sb *Backend) APIs(chain consensus.ChainHeaderReader) []rpc.API {
   291  	return []rpc.API{{
   292  		Namespace: "istanbul",
   293  		Version:   "1.0",
   294  		Service:   &API{chain: chain, backend: sb},
   295  		Public:    true,
   296  	}}
   297  }
   298  
   299  // Start implements consensus.Istanbul.Start
   300  func (sb *Backend) Start(chain consensus.ChainHeaderReader, currentBlock func() *types.Block, hasBadBlock func(db ethdb.Reader, hash common.Hash) bool) error {
   301  	sb.coreMu.Lock()
   302  	defer sb.coreMu.Unlock()
   303  	if sb.coreStarted {
   304  		return istanbul.ErrStartedEngine
   305  	}
   306  
   307  	// clear previous data
   308  	sb.proposedBlockHash = common.Hash{}
   309  	if sb.commitCh != nil {
   310  		close(sb.commitCh)
   311  	}
   312  	sb.commitCh = make(chan *types.Block, 1)
   313  
   314  	sb.chain = chain
   315  	sb.currentBlock = currentBlock
   316  	sb.hasBadBlock = hasBadBlock
   317  
   318  	// Check if qbft Consensus needs to be used after chain is set
   319  	if err := sb.startQBFT(); err != nil {
   320  		return err
   321  	}
   322  
   323  	sb.coreStarted = true
   324  
   325  	return nil
   326  }
   327  
   328  // Stop implements consensus.Istanbul.Stop
   329  func (sb *Backend) Stop() error {
   330  	sb.coreMu.Lock()
   331  	defer sb.coreMu.Unlock()
   332  	if !sb.coreStarted {
   333  		return istanbul.ErrStoppedEngine
   334  	}
   335  	if err := sb.stop(); err != nil {
   336  		return err
   337  	}
   338  	sb.coreStarted = false
   339  
   340  	return nil
   341  }
   342  
   343  func addrsToString(addrs []common.Address) []string {
   344  	strs := make([]string, len(addrs))
   345  	for i, addr := range addrs {
   346  		strs[i] = addr.String()
   347  	}
   348  	return strs
   349  }
   350  
   351  func (sb *Backend) emissionLogger(emission *Emission) log.Logger {
   352  	return sb.logger.New(
   353  		"emission.number", emission.Number,
   354  		"emission.hash", emission.Hash.String(),
   355  		"emission.circulatingsupply", emission.CirculatingSupply,
   356  	)
   357  }
   358  
   359  func (sb *Backend) storeEmission(emission *Emission) error {
   360  	logger := sb.emissionLogger(emission)
   361  	logger.Debug("IBFT: store emission to database")
   362  	if err := emission.store(sb.db); err != nil {
   363  		logger.Error("IBFT: failed to store emission to database", "err", err)
   364  		return err
   365  	}
   366  
   367  	return nil
   368  }
   369  
   370  func (sb *Backend) emission(chain consensus.ChainHeaderReader, number uint64, hash common.Hash, parents []*types.Header) (*Emission, error) {
   371  	var (
   372  		headers  []*types.Header
   373  		emission *Emission
   374  	)
   375  
   376  	for emission == nil {
   377  		// If an in-memory emission was found, use that
   378  		if e, ok := sb.recentsEmission.Get(hash); ok {
   379  			emission = e.(*Emission)
   380  			sb.emissionLogger(emission).Trace("IBFT: loaded emission from cache")
   381  			break
   382  		}
   383  		// If an on-disk checkpoint emission can be found, use that
   384  		if number%checkpointInterval == 0 {
   385  			if s, err := loadEmission(hash, sb.db); err == nil {
   386  				emission = s
   387  				sb.emissionLogger(emission).Trace("IBFT: loaded emission from database")
   388  				break
   389  			}
   390  		}
   391  
   392  		// If we're at block zero, set initial emission
   393  		if number == 0 {
   394  			genesis := chain.GetHeaderByNumber(0)
   395  			if err := sb.EngineForBlockNumber(big.NewInt(0)).VerifyHeader(chain, genesis, nil, nil); err != nil {
   396  				sb.logger.Error("IBFT: invalid genesis block", "err", err)
   397  				return nil, err
   398  			}
   399  
   400  			emission = newEmission(0, genesis.Hash(), chain.Config().GenesisETN)
   401  			if err := sb.storeEmission(emission); err != nil {
   402  				return nil, err
   403  			}
   404  			break
   405  		}
   406  
   407  		// No emission for this header, gather the header and move backward
   408  		var header *types.Header
   409  		if len(parents) > 0 {
   410  			// If we have explicit parents, pick from there (enforced)
   411  			header = parents[len(parents)-1]
   412  			if header.Hash() != hash || header.Number.Uint64() != number {
   413  				return nil, consensus.ErrUnknownAncestor
   414  			}
   415  			parents = parents[:len(parents)-1]
   416  		} else {
   417  			// No explicit parents (or no more left), reach out to the database
   418  			header = chain.GetHeader(hash, number)
   419  			if header == nil {
   420  				return nil, consensus.ErrUnknownAncestor
   421  			}
   422  		}
   423  
   424  		headers = append(headers, header)
   425  		number, hash = number-1, header.ParentHash
   426  	}
   427  
   428  	// Previous emission found, apply any pending headers on top of it
   429  	for i := 0; i < len(headers)/2; i++ {
   430  		headers[i], headers[len(headers)-1-i] = headers[len(headers)-1-i], headers[i]
   431  	}
   432  
   433  	emission, err := sb.emissionApply(chain, emission, headers)
   434  	if err != nil {
   435  		return nil, err
   436  	}
   437  	sb.recentsEmission.Add(emission.Hash, emission)
   438  
   439  	// If we've generated a new checkpoint emission, save to disk
   440  	if emission.Number%checkpointInterval == 0 && len(headers) > 0 {
   441  		if err = sb.storeEmission(emission); err != nil {
   442  			return nil, err
   443  		}
   444  	}
   445  
   446  	return emission, err
   447  }
   448  
   449  func (sb *Backend) emissionApply(chain consensus.ChainHeaderReader, emission *Emission, headers []*types.Header) (*Emission, error) {
   450  	// Allow passing in no headers for cleaner code
   451  	if len(headers) == 0 {
   452  		return emission, nil
   453  	}
   454  	// Sanity check that the headers can be applied
   455  	for i := 0; i < len(headers)-1; i++ {
   456  		if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 {
   457  			return nil, istanbulcommon.ErrInvalidVotingChain
   458  		}
   459  	}
   460  	if headers[0].Number.Uint64() != emission.Number+1 {
   461  		return nil, istanbulcommon.ErrInvalidVotingChain
   462  	}
   463  	// Iterate through the headers and create a new snapshot
   464  	emissionCpy := emission.copy()
   465  
   466  	for _, header := range headers {
   467  		emissionCpy.CirculatingSupply = new(big.Int).Add(emissionCpy.CirculatingSupply, sb.GetBaseBlockReward(chain, header))
   468  	}
   469  	emissionCpy.Number += uint64(len(headers))
   470  	emissionCpy.Hash = headers[len(headers)-1].Hash()
   471  
   472  	return emissionCpy, nil
   473  }
   474  
   475  func (sb *Backend) snapLogger(snap *Snapshot) log.Logger {
   476  	return sb.logger.New(
   477  		"snap.number", snap.Number,
   478  		"snap.hash", snap.Hash.String(),
   479  		"snap.epoch", snap.Epoch,
   480  		"snap.validators", addrsToString(snap.validators()),
   481  		"snap.votes", snap.Votes,
   482  	)
   483  }
   484  
   485  func (sb *Backend) storeSnap(snap *Snapshot) error {
   486  	logger := sb.snapLogger(snap)
   487  	logger.Debug("IBFT: store snapshot to database")
   488  	if err := snap.store(sb.db); err != nil {
   489  		logger.Error("IBFT: failed to store snapshot to database", "err", err)
   490  		return err
   491  	}
   492  
   493  	return nil
   494  }
   495  
   496  // snapshot retrieves the authorization snapshot at a given point in time.
   497  func (sb *Backend) snapshot(chain consensus.ChainHeaderReader, number uint64, hash common.Hash, parents []*types.Header) (*Snapshot, error) {
   498  	// Search for a snapshot in memory or on disk for checkpoints
   499  	var (
   500  		headers []*types.Header
   501  		snap    *Snapshot
   502  	)
   503  	for snap == nil {
   504  		// If an in-memory snapshot was found, use that
   505  		if s, ok := sb.recents.Get(hash); ok {
   506  			snap = s.(*Snapshot)
   507  			sb.snapLogger(snap).Trace("IBFT: loaded voting snapshot from cache")
   508  			break
   509  		}
   510  		// If an on-disk checkpoint snapshot can be found, use that
   511  		if number%checkpointInterval == 0 {
   512  			if s, err := loadSnapshot(sb.config.Epoch, sb.db, hash); err == nil {
   513  				snap = s
   514  				sb.snapLogger(snap).Trace("IBFT: loaded voting snapshot from database")
   515  				break
   516  			}
   517  		}
   518  
   519  		// If we're at block zero, make a snapshot
   520  		if number == 0 {
   521  			genesis := chain.GetHeaderByNumber(0)
   522  			if err := sb.EngineForBlockNumber(big.NewInt(0)).VerifyHeader(chain, genesis, nil, nil); err != nil {
   523  				sb.logger.Error("IBFT: invalid genesis block", "err", err)
   524  				return nil, err
   525  			}
   526  
   527  			// Get the validators from genesis to create a snapshot
   528  			validators, err := sb.EngineForBlockNumber(big.NewInt(0)).Validators(genesis)
   529  			if err != nil {
   530  				sb.logger.Error("IBFT: invalid genesis block", "err", err)
   531  				return nil, err
   532  			}
   533  
   534  			snap = newSnapshot(sb.config.Epoch, 0, genesis.Hash(), validator.NewSet(validators, sb.config.ProposerPolicy))
   535  			if err := sb.storeSnap(snap); err != nil {
   536  				return nil, err
   537  			}
   538  			break
   539  		}
   540  
   541  		// No snapshot for this header, gather the header and move backward
   542  		var header *types.Header
   543  		if len(parents) > 0 {
   544  			// If we have explicit parents, pick from there (enforced)
   545  			header = parents[len(parents)-1]
   546  			if header.Hash() != hash || header.Number.Uint64() != number {
   547  				return nil, consensus.ErrUnknownAncestor
   548  			}
   549  			parents = parents[:len(parents)-1]
   550  		} else {
   551  			// No explicit parents (or no more left), reach out to the database
   552  			header = chain.GetHeader(hash, number)
   553  			if header == nil {
   554  				return nil, consensus.ErrUnknownAncestor
   555  			}
   556  		}
   557  
   558  		headers = append(headers, header)
   559  		number, hash = number-1, header.ParentHash
   560  	}
   561  
   562  	// Previous snapshot found, apply any pending headers on top of it
   563  	for i := 0; i < len(headers)/2; i++ {
   564  		headers[i], headers[len(headers)-1-i] = headers[len(headers)-1-i], headers[i]
   565  	}
   566  
   567  	snap, err := sb.snapApply(snap, headers)
   568  	if err != nil {
   569  		return nil, err
   570  	}
   571  	sb.recents.Add(snap.Hash, snap)
   572  
   573  	// If we've generated a new checkpoint snapshot, save to disk
   574  	if snap.Number%checkpointInterval == 0 && len(headers) > 0 {
   575  		if err = sb.storeSnap(snap); err != nil {
   576  			return nil, err
   577  		}
   578  	}
   579  
   580  	return snap, err
   581  }
   582  
   583  // SealHash returns the hash of a block prior to it being sealed.
   584  func (sb *Backend) SealHash(header *types.Header) common.Hash {
   585  	return sb.EngineForBlockNumber(header.Number).SealHash(header)
   586  }
   587  
   588  func (sb *Backend) snapApply(snap *Snapshot, headers []*types.Header) (*Snapshot, error) {
   589  	// Allow passing in no headers for cleaner code
   590  	if len(headers) == 0 {
   591  		return snap, nil
   592  	}
   593  	// Sanity check that the headers can be applied
   594  	for i := 0; i < len(headers)-1; i++ {
   595  		if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 {
   596  			return nil, istanbulcommon.ErrInvalidVotingChain
   597  		}
   598  	}
   599  	if headers[0].Number.Uint64() != snap.Number+1 {
   600  		return nil, istanbulcommon.ErrInvalidVotingChain
   601  	}
   602  	// Iterate through the headers and create a new snapshot
   603  	snapCpy := snap.copy()
   604  
   605  	for _, header := range headers {
   606  		err := sb.snapApplyHeader(snapCpy, header)
   607  		if err != nil {
   608  			return nil, err
   609  		}
   610  	}
   611  	snapCpy.Number += uint64(len(headers))
   612  	snapCpy.Hash = headers[len(headers)-1].Hash()
   613  
   614  	return snapCpy, nil
   615  }
   616  
   617  func (sb *Backend) snapApplyHeader(snap *Snapshot, header *types.Header) error {
   618  	logger := sb.snapLogger(snap).New("header.number", header.Number.Uint64(), "header.hash", header.Hash().String())
   619  
   620  	logger.Trace("IBFT: apply header to voting snapshot")
   621  
   622  	// Remove any votes on checkpoint blocks
   623  	number := header.Number.Uint64()
   624  	if number%snap.Epoch == 0 {
   625  		snap.Votes = nil
   626  		snap.Tally = make(map[common.Address]Tally)
   627  	}
   628  
   629  	// Resolve the authorization key and check against validators
   630  	validator, err := sb.EngineForBlockNumber(header.Number).Author(header)
   631  	if err != nil {
   632  		logger.Error("IBFT: invalid header author", "err", err)
   633  		return err
   634  	}
   635  
   636  	logger = logger.New("header.author", validator)
   637  
   638  	if _, v := snap.ValSet.GetByAddress(validator); v == nil {
   639  		logger.Error("IBFT: header author is not a validator")
   640  		return istanbulcommon.ErrUnauthorized
   641  	}
   642  
   643  	// Read vote from header
   644  	candidate, authorize, err := sb.EngineForBlockNumber(header.Number).ReadVote(header)
   645  	if err != nil {
   646  		logger.Error("IBFT: invalid header vote", "err", err)
   647  		return err
   648  	}
   649  
   650  	logger = logger.New("candidate", candidate.String(), "authorize", authorize)
   651  	// Header authorized, discard any previous votes from the validator
   652  	for i, vote := range snap.Votes {
   653  		if vote.Validator == validator && vote.Address == candidate {
   654  			logger.Trace("IBFT: discard previous vote from tally", "old.authorize", vote.Authorize)
   655  			// Uncast the vote from the cached tally
   656  			snap.uncast(vote.Address, vote.Authorize)
   657  
   658  			// Uncast the vote from the chronological list
   659  			snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
   660  			break // only one vote allowed
   661  		}
   662  	}
   663  
   664  	logger.Debug("IBFT: add vote to tally")
   665  	if snap.cast(candidate, authorize) {
   666  		snap.Votes = append(snap.Votes, &Vote{
   667  			Validator: validator,
   668  			Block:     number,
   669  			Address:   candidate,
   670  			Authorize: authorize,
   671  		})
   672  	}
   673  
   674  	// If the vote passed, update the list of validators
   675  	if tally := snap.Tally[candidate]; tally.Votes > snap.ValSet.Size()/2 {
   676  		if tally.Authorize {
   677  			logger.Info("IBFT: reached majority to add validator")
   678  			snap.ValSet.AddValidator(candidate)
   679  		} else {
   680  			logger.Info("IBFT: reached majority to remove validator")
   681  			snap.ValSet.RemoveValidator(candidate)
   682  
   683  			// Discard any previous votes the deauthorized validator cast
   684  			for i := 0; i < len(snap.Votes); i++ {
   685  				if snap.Votes[i].Validator == candidate {
   686  					// Uncast the vote from the cached tally
   687  					snap.uncast(snap.Votes[i].Address, snap.Votes[i].Authorize)
   688  
   689  					// Uncast the vote from the chronological list
   690  					snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
   691  
   692  					i--
   693  				}
   694  			}
   695  		}
   696  		// Discard any previous votes around the just changed account
   697  		for i := 0; i < len(snap.Votes); i++ {
   698  			if snap.Votes[i].Address == candidate {
   699  				snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
   700  				i--
   701  			}
   702  		}
   703  		delete(snap.Tally, candidate)
   704  	}
   705  	return nil
   706  }