github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/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/kisexp/xdchain/common"
    25  	"github.com/kisexp/xdchain/consensus"
    26  	"github.com/kisexp/xdchain/consensus/istanbul"
    27  	istanbulcommon "github.com/kisexp/xdchain/consensus/istanbul/common"
    28  	"github.com/kisexp/xdchain/consensus/istanbul/validator"
    29  	"github.com/kisexp/xdchain/core/state"
    30  	"github.com/kisexp/xdchain/core/types"
    31  	"github.com/kisexp/xdchain/log"
    32  	"github.com/kisexp/xdchain/rpc"
    33  )
    34  
    35  const (
    36  	checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database
    37  	inmemorySnapshots  = 128  // Number of recent vote snapshots to keep in memory
    38  	inmemoryPeers      = 40
    39  	inmemoryMessages   = 1024
    40  )
    41  
    42  // Author retrieves the Ethereum address of the account that minted the given
    43  // block, which may be different from the header's coinbase if a consensus
    44  // engine is based on signatures.
    45  func (sb *Backend) Author(header *types.Header) (common.Address, error) {
    46  	return sb.EngineForBlockNumber(header.Number).Author(header)
    47  }
    48  
    49  // Signers extracts all the addresses who have signed the given header
    50  // It will extract for each seal who signed it, regardless of if the seal is
    51  // repeated
    52  func (sb *Backend) Signers(header *types.Header) ([]common.Address, error) {
    53  	return sb.EngineForBlockNumber(header.Number).Signers(header)
    54  }
    55  
    56  // VerifyHeader checks whether a header conforms to the consensus rules of a
    57  // given engine. Verifying the seal may be done optionally here, or explicitly
    58  // via the VerifySeal method.
    59  func (sb *Backend) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error {
    60  	return sb.verifyHeader(chain, header, nil)
    61  }
    62  
    63  func (sb *Backend) verifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) error {
    64  	// Assemble the voting snapshot
    65  	snap, err := sb.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, parents)
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	return sb.EngineForBlockNumber(header.Number).VerifyHeader(chain, header, parents, snap.ValSet)
    71  }
    72  
    73  // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
    74  // concurrently. The method returns a quit channel to abort the operations and
    75  // a results channel to retrieve the async verifications (the order is that of
    76  // the input slice).
    77  func (sb *Backend) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
    78  	abort := make(chan struct{})
    79  	results := make(chan error, len(headers))
    80  	go func() {
    81  		errored := false
    82  		for i, header := range headers {
    83  			var err error
    84  			if errored {
    85  				err = consensus.ErrUnknownAncestor
    86  			} else {
    87  				err = sb.verifyHeader(chain, header, headers[:i])
    88  			}
    89  
    90  			if err != nil {
    91  				errored = true
    92  			}
    93  
    94  			select {
    95  			case <-abort:
    96  				return
    97  			case results <- err:
    98  			}
    99  		}
   100  	}()
   101  	return abort, results
   102  }
   103  
   104  // VerifyUncles verifies that the given block's uncles conform to the consensus
   105  // rules of a given engine.
   106  func (sb *Backend) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
   107  	return sb.EngineForBlockNumber(block.Header().Number).VerifyUncles(chain, block)
   108  }
   109  
   110  // VerifySeal checks whether the crypto seal on a header is valid according to
   111  // the consensus rules of the given engine.
   112  func (sb *Backend) VerifySeal(chain consensus.ChainHeaderReader, header *types.Header) error {
   113  	// get parent header and ensure the signer is in parent's validator set
   114  	number := header.Number.Uint64()
   115  	if number == 0 {
   116  		return istanbulcommon.ErrUnknownBlock
   117  	}
   118  
   119  	// Assemble the voting snapshot
   120  	snap, err := sb.snapshot(chain, number-1, header.ParentHash, nil)
   121  	if err != nil {
   122  		return err
   123  	}
   124  
   125  	return sb.EngineForBlockNumber(header.Number).VerifySeal(chain, header, snap.ValSet)
   126  }
   127  
   128  // Prepare initializes the consensus fields of a block header according to the
   129  // rules of a particular engine. The changes are executed inline.
   130  func (sb *Backend) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
   131  	// Assemble the voting snapshot
   132  	snap, err := sb.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, nil)
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	err = sb.EngineForBlockNumber(header.Number).Prepare(chain, header, snap.ValSet)
   138  	if err != nil {
   139  		return err
   140  	}
   141  
   142  	// get valid candidate list
   143  	sb.candidatesLock.RLock()
   144  	var addresses []common.Address
   145  	var authorizes []bool
   146  	for address, authorize := range sb.candidates {
   147  		if snap.checkVote(address, authorize) {
   148  			addresses = append(addresses, address)
   149  			authorizes = append(authorizes, authorize)
   150  		}
   151  	}
   152  	sb.candidatesLock.RUnlock()
   153  
   154  	if len(addresses) > 0 {
   155  		index := rand.Intn(len(addresses))
   156  
   157  		err = sb.EngineForBlockNumber(header.Number).WriteVote(header, addresses[index], authorizes[index])
   158  		if err != nil {
   159  			log.Error("BFT: error writing validator vote", "err", err)
   160  			return err
   161  		}
   162  	}
   163  
   164  	return nil
   165  }
   166  
   167  // Finalize runs any post-transaction state modifications (e.g. block rewards)
   168  // and assembles the final block.
   169  //
   170  // Note, the block header and state database might be updated to reflect any
   171  // consensus rules that happen at finalization (e.g. block rewards).
   172  func (sb *Backend) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {
   173  	sb.EngineForBlockNumber(header.Number).Finalize(chain, header, state, txs, uncles)
   174  }
   175  
   176  // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
   177  // nor block rewards given, and returns the final block.
   178  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) {
   179  	return sb.EngineForBlockNumber(header.Number).FinalizeAndAssemble(chain, header, state, txs, uncles, receipts)
   180  }
   181  
   182  // Seal generates a new block for the given input block with the local miner's
   183  // seal place on top.
   184  func (sb *Backend) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
   185  	// update the block header timestamp and signature and propose the block to core engine
   186  	header := block.Header()
   187  	number := header.Number.Uint64()
   188  
   189  	// Bail out if we're unauthorized to sign a block
   190  	snap, err := sb.snapshot(chain, number-1, header.ParentHash, nil)
   191  	if err != nil {
   192  		return err
   193  	}
   194  
   195  	block, err = sb.EngineForBlockNumber(header.Number).Seal(chain, block, snap.ValSet)
   196  	if err != nil {
   197  		return err
   198  	}
   199  
   200  	delay := time.Until(time.Unix(int64(block.Header().Time), 0))
   201  
   202  	go func() {
   203  		// wait for the timestamp of header, use this to adjust the block period
   204  		select {
   205  		case <-time.After(delay):
   206  		case <-stop:
   207  			results <- nil
   208  			return
   209  		}
   210  
   211  		// get the proposed block hash and clear it if the seal() is completed.
   212  		sb.sealMu.Lock()
   213  		sb.proposedBlockHash = block.Hash()
   214  
   215  		defer func() {
   216  			sb.proposedBlockHash = common.Hash{}
   217  			sb.sealMu.Unlock()
   218  		}()
   219  		// post block into Istanbul engine
   220  		go sb.EventMux().Post(istanbul.RequestEvent{
   221  			Proposal: block,
   222  		})
   223  		for {
   224  			select {
   225  			case result := <-sb.commitCh:
   226  				// if the block hash and the hash from channel are the same,
   227  				// return the result. Otherwise, keep waiting the next hash.
   228  				if result != nil && block.Hash() == result.Hash() {
   229  					results <- result
   230  					return
   231  				}
   232  			case <-stop:
   233  				results <- nil
   234  				return
   235  			}
   236  		}
   237  	}()
   238  	return nil
   239  }
   240  
   241  // APIs returns the RPC APIs this consensus engine provides.
   242  func (sb *Backend) APIs(chain consensus.ChainHeaderReader) []rpc.API {
   243  	return []rpc.API{{
   244  		Namespace: "istanbul",
   245  		Version:   "1.0",
   246  		Service:   &API{chain: chain, backend: sb},
   247  		Public:    true,
   248  	}}
   249  }
   250  
   251  // Start implements consensus.Istanbul.Start
   252  func (sb *Backend) Start(chain consensus.ChainHeaderReader, currentBlock func() *types.Block, hasBadBlock func(hash common.Hash) bool) error {
   253  	sb.coreMu.Lock()
   254  	defer sb.coreMu.Unlock()
   255  	if sb.coreStarted {
   256  		return istanbul.ErrStartedEngine
   257  	}
   258  
   259  	// clear previous data
   260  	sb.proposedBlockHash = common.Hash{}
   261  	if sb.commitCh != nil {
   262  		close(sb.commitCh)
   263  	}
   264  	sb.commitCh = make(chan *types.Block, 1)
   265  
   266  	sb.chain = chain
   267  	sb.currentBlock = currentBlock
   268  	sb.hasBadBlock = hasBadBlock
   269  
   270  	// Check if qbft Consensus needs to be used after chain is set
   271  	var err error
   272  	if sb.IsQBFTConsensus() {
   273  		err = sb.startQBFT()
   274  	} else {
   275  		err = sb.startIBFT()
   276  	}
   277  
   278  	if err != nil {
   279  		return err
   280  	}
   281  
   282  	sb.coreStarted = true
   283  
   284  	return nil
   285  }
   286  
   287  // Stop implements consensus.Istanbul.Stop
   288  func (sb *Backend) Stop() error {
   289  	sb.coreMu.Lock()
   290  	defer sb.coreMu.Unlock()
   291  	if !sb.coreStarted {
   292  		return istanbul.ErrStoppedEngine
   293  	}
   294  	if err := sb.stop(); err != nil {
   295  		return err
   296  	}
   297  	sb.coreStarted = false
   298  
   299  	return nil
   300  }
   301  
   302  func addrsToString(addrs []common.Address) []string {
   303  	strs := make([]string, len(addrs))
   304  	for i, addr := range addrs {
   305  		strs[i] = addr.String()
   306  	}
   307  	return strs
   308  }
   309  
   310  func (sb *Backend) snapLogger(snap *Snapshot) log.Logger {
   311  	return sb.logger.New(
   312  		"snap.number", snap.Number,
   313  		"snap.hash", snap.Hash.String(),
   314  		"snap.epoch", snap.Epoch,
   315  		"snap.validators", addrsToString(snap.validators()),
   316  		"snap.votes", snap.Votes,
   317  	)
   318  }
   319  
   320  func (sb *Backend) storeSnap(snap *Snapshot) error {
   321  	logger := sb.snapLogger(snap)
   322  	logger.Debug("BFT: store snapshot to database")
   323  	if err := snap.store(sb.db); err != nil {
   324  		logger.Error("BFT: failed to store snapshot to database", "err", err)
   325  		return err
   326  	}
   327  
   328  	return nil
   329  }
   330  
   331  // snapshot retrieves the authorization snapshot at a given point in time.
   332  func (sb *Backend) snapshot(chain consensus.ChainHeaderReader, number uint64, hash common.Hash, parents []*types.Header) (*Snapshot, error) {
   333  	// Search for a snapshot in memory or on disk for checkpoints
   334  	var (
   335  		headers []*types.Header
   336  		snap    *Snapshot
   337  	)
   338  	for snap == nil {
   339  		// If an in-memory snapshot was found, use that
   340  		if s, ok := sb.recents.Get(hash); ok {
   341  			snap = s.(*Snapshot)
   342  			sb.snapLogger(snap).Trace("BFT: loaded voting snapshot from cache")
   343  			break
   344  		}
   345  		// If an on-disk checkpoint snapshot can be found, use that
   346  		if number%checkpointInterval == 0 {
   347  			if s, err := loadSnapshot(sb.config.Epoch, sb.db, hash); err == nil {
   348  				snap = s
   349  				sb.snapLogger(snap).Trace("BFT: loaded voting snapshot from database")
   350  				break
   351  			}
   352  		}
   353  
   354  		// If we're at block zero, make a snapshot
   355  		if number == 0 {
   356  			genesis := chain.GetHeaderByNumber(0)
   357  			if err := sb.EngineForBlockNumber(big.NewInt(0)).VerifyHeader(chain, genesis, nil, nil); err != nil {
   358  				sb.logger.Error("BFT: invalid genesis block", "err", err)
   359  				return nil, err
   360  			}
   361  
   362  			// Get the validators from genesis to create a snapshot
   363  			validators, err := sb.EngineForBlockNumber(big.NewInt(0)).Validators(genesis)
   364  			if err != nil {
   365  				sb.logger.Error("BFT: invalid genesis block", "err", err)
   366  				return nil, err
   367  			}
   368  
   369  			snap = newSnapshot(sb.config.Epoch, 0, genesis.Hash(), validator.NewSet(validators, sb.config.ProposerPolicy))
   370  			if err := sb.storeSnap(snap); err != nil {
   371  				return nil, err
   372  			}
   373  			break
   374  		}
   375  
   376  		// No snapshot for this header, gather the header and move backward
   377  		var header *types.Header
   378  		if len(parents) > 0 {
   379  			// If we have explicit parents, pick from there (enforced)
   380  			header = parents[len(parents)-1]
   381  			if header.Hash() != hash || header.Number.Uint64() != number {
   382  				return nil, consensus.ErrUnknownAncestor
   383  			}
   384  			parents = parents[:len(parents)-1]
   385  		} else {
   386  			// No explicit parents (or no more left), reach out to the database
   387  			header = chain.GetHeader(hash, number)
   388  			if header == nil {
   389  				return nil, consensus.ErrUnknownAncestor
   390  			}
   391  		}
   392  
   393  		headers = append(headers, header)
   394  		number, hash = number-1, header.ParentHash
   395  	}
   396  
   397  	// Previous snapshot found, apply any pending headers on top of it
   398  	for i := 0; i < len(headers)/2; i++ {
   399  		headers[i], headers[len(headers)-1-i] = headers[len(headers)-1-i], headers[i]
   400  	}
   401  
   402  	snap, err := sb.snapApply(snap, headers)
   403  	if err != nil {
   404  		return nil, err
   405  	}
   406  	sb.recents.Add(snap.Hash, snap)
   407  
   408  	// If we've generated a new checkpoint snapshot, save to disk
   409  	if snap.Number%checkpointInterval == 0 && len(headers) > 0 {
   410  		if err = sb.storeSnap(snap); err != nil {
   411  			return nil, err
   412  		}
   413  	}
   414  
   415  	return snap, err
   416  }
   417  
   418  // SealHash returns the hash of a block prior to it being sealed.
   419  func (sb *Backend) SealHash(header *types.Header) common.Hash {
   420  	return sb.EngineForBlockNumber(header.Number).SealHash(header)
   421  }
   422  
   423  func (sb *Backend) snapApply(snap *Snapshot, headers []*types.Header) (*Snapshot, error) {
   424  	// Allow passing in no headers for cleaner code
   425  	if len(headers) == 0 {
   426  		return snap, nil
   427  	}
   428  	// Sanity check that the headers can be applied
   429  	for i := 0; i < len(headers)-1; i++ {
   430  		if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 {
   431  			return nil, istanbulcommon.ErrInvalidVotingChain
   432  		}
   433  	}
   434  	if headers[0].Number.Uint64() != snap.Number+1 {
   435  		return nil, istanbulcommon.ErrInvalidVotingChain
   436  	}
   437  	// Iterate through the headers and create a new snapshot
   438  	snapCpy := snap.copy()
   439  
   440  	for _, header := range headers {
   441  		err := sb.snapApplyHeader(snapCpy, header)
   442  		if err != nil {
   443  			return nil, err
   444  		}
   445  	}
   446  	snapCpy.Number += uint64(len(headers))
   447  	snapCpy.Hash = headers[len(headers)-1].Hash()
   448  
   449  	return snapCpy, nil
   450  }
   451  
   452  func (sb *Backend) snapApplyHeader(snap *Snapshot, header *types.Header) error {
   453  	logger := sb.snapLogger(snap).New("header.number", header.Number.Uint64(), "header.hash", header.Hash().String())
   454  
   455  	logger.Trace("BFT: apply header to voting snapshot")
   456  
   457  	// Remove any votes on checkpoint blocks
   458  	number := header.Number.Uint64()
   459  	if number%snap.Epoch == 0 {
   460  		snap.Votes = nil
   461  		snap.Tally = make(map[common.Address]Tally)
   462  	}
   463  
   464  	// Resolve the authorization key and check against validators
   465  	validator, err := sb.EngineForBlockNumber(header.Number).Author(header)
   466  	if err != nil {
   467  		logger.Error("BFT: invalid header author", "err", err)
   468  		return err
   469  	}
   470  
   471  	logger = logger.New("header.author", validator)
   472  
   473  	if _, v := snap.ValSet.GetByAddress(validator); v == nil {
   474  		logger.Error("BFT: header author is not a validator")
   475  		return istanbulcommon.ErrUnauthorized
   476  	}
   477  
   478  	// Read vote from header
   479  	candidate, authorize, err := sb.EngineForBlockNumber(header.Number).ReadVote(header)
   480  	if err != nil {
   481  		logger.Error("BFT: invalid header vote", "err", err)
   482  		return err
   483  	}
   484  
   485  	logger = logger.New("candidate", candidate.String(), "authorize", authorize)
   486  	// Header authorized, discard any previous votes from the validator
   487  	for i, vote := range snap.Votes {
   488  		if vote.Validator == validator && vote.Address == candidate {
   489  			logger.Trace("BFT: discard previous vote from tally", "old.authorize", vote.Authorize)
   490  			// Uncast the vote from the cached tally
   491  			snap.uncast(vote.Address, vote.Authorize)
   492  
   493  			// Uncast the vote from the chronological list
   494  			snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
   495  			break // only one vote allowed
   496  		}
   497  	}
   498  
   499  	logger.Debug("BFT: add vote to tally")
   500  	if snap.cast(candidate, authorize) {
   501  		snap.Votes = append(snap.Votes, &Vote{
   502  			Validator: validator,
   503  			Block:     number,
   504  			Address:   candidate,
   505  			Authorize: authorize,
   506  		})
   507  	}
   508  
   509  	// If the vote passed, update the list of validators
   510  	if tally := snap.Tally[candidate]; tally.Votes > snap.ValSet.Size()/2 {
   511  
   512  		if tally.Authorize {
   513  			logger.Info("BFT: reached majority to add validator")
   514  			snap.ValSet.AddValidator(candidate)
   515  		} else {
   516  			logger.Info("BFT: reached majority to remove validator")
   517  			snap.ValSet.RemoveValidator(candidate)
   518  
   519  			// Discard any previous votes the deauthorized validator cast
   520  			for i := 0; i < len(snap.Votes); i++ {
   521  				if snap.Votes[i].Validator == candidate {
   522  					// Uncast the vote from the cached tally
   523  					snap.uncast(snap.Votes[i].Address, snap.Votes[i].Authorize)
   524  
   525  					// Uncast the vote from the chronological list
   526  					snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
   527  
   528  					i--
   529  				}
   530  			}
   531  		}
   532  		// Discard any previous votes around the just changed account
   533  		for i := 0; i < len(snap.Votes); i++ {
   534  			if snap.Votes[i].Address == candidate {
   535  				snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
   536  				i--
   537  			}
   538  		}
   539  		delete(snap.Tally, candidate)
   540  	}
   541  	return nil
   542  }