github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/consensus/istanbul/qbft/engine/engine.go (about)

     1  package qbftengine
     2  
     3  import (
     4  	"bytes"
     5  	"math/big"
     6  	"time"
     7  
     8  	"github.com/kisexp/xdchain/common"
     9  	"github.com/kisexp/xdchain/consensus"
    10  	"github.com/kisexp/xdchain/consensus/istanbul"
    11  	istanbulcommon "github.com/kisexp/xdchain/consensus/istanbul/common"
    12  	"github.com/kisexp/xdchain/consensus/istanbul/validator"
    13  	"github.com/kisexp/xdchain/core/state"
    14  	"github.com/kisexp/xdchain/core/types"
    15  	"github.com/kisexp/xdchain/rlp"
    16  	"github.com/kisexp/xdchain/trie"
    17  	"golang.org/x/crypto/sha3"
    18  )
    19  
    20  var (
    21  	nilUncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.
    22  )
    23  
    24  type SignerFn func(data []byte) ([]byte, error)
    25  
    26  type Engine struct {
    27  	cfg *istanbul.Config
    28  
    29  	signer common.Address // Ethereum address of the signing key
    30  	sign   SignerFn       // Signer function to authorize hashes with
    31  }
    32  
    33  func NewEngine(cfg *istanbul.Config, signer common.Address, sign SignerFn) *Engine {
    34  	return &Engine{
    35  		cfg:    cfg,
    36  		signer: signer,
    37  		sign:   sign,
    38  	}
    39  }
    40  
    41  func (e *Engine) Author(header *types.Header) (common.Address, error) {
    42  	return header.Coinbase, nil
    43  }
    44  
    45  func (e *Engine) CommitHeader(header *types.Header, seals [][]byte, round *big.Int) error {
    46  	return ApplyHeaderQBFTExtra(
    47  		header,
    48  		writeCommittedSeals(seals),
    49  		writeRoundNumber(round),
    50  	)
    51  }
    52  
    53  // writeCommittedSeals writes the extra-data field of a block header with given committed seals.
    54  func writeCommittedSeals(committedSeals [][]byte) ApplyQBFTExtra {
    55  	return func(qbftExtra *types.QBFTExtra) error {
    56  		if len(committedSeals) == 0 {
    57  			return istanbulcommon.ErrInvalidCommittedSeals
    58  		}
    59  
    60  		for _, seal := range committedSeals {
    61  			if len(seal) != types.IstanbulExtraSeal {
    62  				return istanbulcommon.ErrInvalidCommittedSeals
    63  			}
    64  		}
    65  
    66  		qbftExtra.CommittedSeal = make([][]byte, len(committedSeals))
    67  		copy(qbftExtra.CommittedSeal, committedSeals)
    68  
    69  		return nil
    70  	}
    71  }
    72  
    73  // writeRoundNumber writes the extra-data field of a block header with given round.
    74  func writeRoundNumber(round *big.Int) ApplyQBFTExtra {
    75  	return func(qbftExtra *types.QBFTExtra) error {
    76  		qbftExtra.Round = uint32(round.Uint64())
    77  		return nil
    78  	}
    79  }
    80  
    81  func (e *Engine) VerifyBlockProposal(chain consensus.ChainHeaderReader, block *types.Block, validators istanbul.ValidatorSet) (time.Duration, error) {
    82  	// check block body
    83  	txnHash := types.DeriveSha(block.Transactions(), new(trie.Trie))
    84  	if txnHash != block.Header().TxHash {
    85  		return 0, istanbulcommon.ErrMismatchTxhashes
    86  	}
    87  
    88  	uncleHash := types.CalcUncleHash(block.Uncles())
    89  	if uncleHash != nilUncleHash {
    90  		return 0, istanbulcommon.ErrInvalidUncleHash
    91  	}
    92  
    93  	// verify the header of proposed block
    94  	err := e.VerifyHeader(chain, block.Header(), nil, validators)
    95  	if err == nil || err == istanbulcommon.ErrEmptyCommittedSeals {
    96  		// ignore errEmptyCommittedSeals error because we don't have the committed seals yet
    97  		return 0, nil
    98  	} else if err == consensus.ErrFutureBlock {
    99  		return time.Until(time.Unix(int64(block.Header().Time), 0)), consensus.ErrFutureBlock
   100  	}
   101  
   102  	return 0, err
   103  }
   104  
   105  func (e *Engine) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, validators istanbul.ValidatorSet) error {
   106  	return e.verifyHeader(chain, header, parents, validators)
   107  }
   108  
   109  // verifyHeader checks whether a header conforms to the consensus rules.The
   110  // caller may optionally pass in a batch of parents (ascending order) to avoid
   111  // looking those up from the database. This is useful for concurrently verifying
   112  // a batch of new headers.
   113  func (e *Engine) verifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, validators istanbul.ValidatorSet) error {
   114  	if header.Number == nil {
   115  		return istanbulcommon.ErrUnknownBlock
   116  	}
   117  
   118  	// Don't waste time checking blocks from the future (adjusting for allowed threshold)
   119  	adjustedTimeNow := time.Now().Add(time.Duration(e.cfg.AllowedFutureBlockTime) * time.Second).Unix()
   120  	if header.Time > uint64(adjustedTimeNow) {
   121  		return consensus.ErrFutureBlock
   122  	}
   123  
   124  	if _, err := types.ExtractQBFTExtra(header); err != nil {
   125  		return istanbulcommon.ErrInvalidExtraDataFormat
   126  	}
   127  
   128  	// Ensure that the mix digest is zero as we don't have fork protection currently
   129  	if header.MixDigest != types.IstanbulDigest {
   130  		return istanbulcommon.ErrInvalidMixDigest
   131  	}
   132  
   133  	// Ensure that the block doesn't contain any uncles which are meaningless in Istanbul
   134  	if header.UncleHash != nilUncleHash {
   135  		return istanbulcommon.ErrInvalidUncleHash
   136  	}
   137  
   138  	// Ensure that the block's difficulty is meaningful (may not be correct at this point)
   139  	if header.Difficulty == nil || header.Difficulty.Cmp(istanbulcommon.DefaultDifficulty) != 0 {
   140  		return istanbulcommon.ErrInvalidDifficulty
   141  	}
   142  
   143  	return e.verifyCascadingFields(chain, header, validators, parents)
   144  }
   145  
   146  func (e *Engine) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool, validators istanbul.ValidatorSet) (chan<- struct{}, <-chan error) {
   147  	abort := make(chan struct{})
   148  	results := make(chan error, len(headers))
   149  	go func() {
   150  		errored := false
   151  		for i, header := range headers {
   152  			var err error
   153  			if errored {
   154  				err = consensus.ErrUnknownAncestor
   155  			} else {
   156  				err = e.verifyHeader(chain, header, headers[:i], validators)
   157  			}
   158  
   159  			if err != nil {
   160  				errored = true
   161  			}
   162  
   163  			select {
   164  			case <-abort:
   165  				return
   166  			case results <- err:
   167  			}
   168  		}
   169  	}()
   170  	return abort, results
   171  }
   172  
   173  // verifyCascadingFields verifies all the header fields that are not standalone,
   174  // rather depend on a batch of previous headers. The caller may optionally pass
   175  // in a batch of parents (ascending order) to avoid looking those up from the
   176  // database. This is useful for concurrently verifying a batch of new headers.
   177  func (e *Engine) verifyCascadingFields(chain consensus.ChainHeaderReader, header *types.Header, validators istanbul.ValidatorSet, parents []*types.Header) error {
   178  	// The genesis block is the always valid dead-end
   179  	number := header.Number.Uint64()
   180  	if number == 0 {
   181  		return nil
   182  	}
   183  
   184  	// Check parent
   185  	var parent *types.Header
   186  	if len(parents) > 0 {
   187  		parent = parents[len(parents)-1]
   188  	} else {
   189  		parent = chain.GetHeader(header.ParentHash, number-1)
   190  	}
   191  
   192  	// Ensure that the block's parent has right number and hash
   193  	if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
   194  		return consensus.ErrUnknownAncestor
   195  	}
   196  
   197  	// Ensure that the block's timestamp isn't too close to it's parent
   198  	if parent.Time+e.cfg.BlockPeriod > header.Time {
   199  		return istanbulcommon.ErrInvalidTimestamp
   200  	}
   201  
   202  	// Verify signer
   203  	if err := e.verifySigner(chain, header, parents, validators); err != nil {
   204  		return err
   205  	}
   206  
   207  	return e.verifyCommittedSeals(chain, header, parents, validators)
   208  }
   209  
   210  func (e *Engine) verifySigner(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, validators istanbul.ValidatorSet) error {
   211  	// Verifying the genesis block is not supported
   212  	number := header.Number.Uint64()
   213  	if number == 0 {
   214  		return istanbulcommon.ErrUnknownBlock
   215  	}
   216  
   217  	// Resolve the authorization key and check against signers
   218  	signer, err := e.Author(header)
   219  	if err != nil {
   220  		return err
   221  	}
   222  
   223  	// Signer should be in the validator set of previous block's extraData.
   224  	if _, v := validators.GetByAddress(signer); v == nil {
   225  		return istanbulcommon.ErrUnauthorized
   226  	}
   227  
   228  	return nil
   229  }
   230  
   231  // verifyCommittedSeals checks whether every committed seal is signed by one of the parent's validators
   232  func (e *Engine) verifyCommittedSeals(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, validators istanbul.ValidatorSet) error {
   233  	number := header.Number.Uint64()
   234  
   235  	if number == 0 {
   236  		// We don't need to verify committed seals in the genesis block
   237  		return nil
   238  	}
   239  
   240  	extra, err := types.ExtractQBFTExtra(header)
   241  	if err != nil {
   242  		return err
   243  	}
   244  	committedSeal := extra.CommittedSeal
   245  
   246  	// The length of Committed seals should be larger than 0
   247  	if len(committedSeal) == 0 {
   248  		return istanbulcommon.ErrEmptyCommittedSeals
   249  	}
   250  
   251  	validatorsCpy := validators.Copy()
   252  
   253  	// Check whether the committed seals are generated by validators
   254  	validSeal := 0
   255  	committers, err := e.Signers(header)
   256  	if err != nil {
   257  		return err
   258  	}
   259  
   260  	for _, addr := range committers {
   261  		if validatorsCpy.RemoveValidator(addr) {
   262  			validSeal++
   263  			continue
   264  		}
   265  		return istanbulcommon.ErrInvalidCommittedSeals
   266  	}
   267  
   268  	// The length of validSeal should be larger than number of faulty node + 1
   269  	if validSeal <= validators.F() {
   270  		return istanbulcommon.ErrInvalidCommittedSeals
   271  	}
   272  
   273  	return nil
   274  }
   275  
   276  // VerifyUncles verifies that the given block's uncles conform to the consensus
   277  // rules of a given engine.
   278  func (e *Engine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
   279  	if len(block.Uncles()) > 0 {
   280  		return istanbulcommon.ErrInvalidUncleHash
   281  	}
   282  	return nil
   283  }
   284  
   285  // VerifySeal checks whether the crypto seal on a header is valid according to
   286  // the consensus rules of the given engine.
   287  func (e *Engine) VerifySeal(chain consensus.ChainHeaderReader, header *types.Header, validators istanbul.ValidatorSet) error {
   288  	// get parent header and ensure the signer is in parent's validator set
   289  	number := header.Number.Uint64()
   290  	if number == 0 {
   291  		return istanbulcommon.ErrUnknownBlock
   292  	}
   293  
   294  	// ensure that the difficulty equals to istanbulcommon.DefaultDifficulty
   295  	if header.Difficulty.Cmp(istanbulcommon.DefaultDifficulty) != 0 {
   296  		return istanbulcommon.ErrInvalidDifficulty
   297  	}
   298  
   299  	return e.verifySigner(chain, header, nil, validators)
   300  }
   301  
   302  func (e *Engine) Prepare(chain consensus.ChainHeaderReader, header *types.Header, validators istanbul.ValidatorSet) error {
   303  	header.Coinbase = common.Address{}
   304  	header.Nonce = istanbulcommon.EmptyBlockNonce
   305  	header.MixDigest = types.IstanbulDigest
   306  
   307  	// copy the parent extra data as the header extra data
   308  	number := header.Number.Uint64()
   309  
   310  	parent := chain.GetHeader(header.ParentHash, number-1)
   311  	if parent == nil {
   312  		return consensus.ErrUnknownAncestor
   313  	}
   314  
   315  	// use the same difficulty for all blocks
   316  	header.Difficulty = istanbulcommon.DefaultDifficulty
   317  
   318  	// set header's timestamp
   319  	header.Time = parent.Time + e.cfg.BlockPeriod
   320  	if header.Time < uint64(time.Now().Unix()) {
   321  		header.Time = uint64(time.Now().Unix())
   322  	}
   323  
   324  	// add validators in snapshot to extraData's validators section
   325  	return ApplyHeaderQBFTExtra(
   326  		header,
   327  		WriteValidators(validator.SortedAddresses(validators.List())),
   328  	)
   329  }
   330  
   331  func WriteValidators(validators []common.Address) ApplyQBFTExtra {
   332  	return func(qbftExtra *types.QBFTExtra) error {
   333  		qbftExtra.Validators = validators
   334  		return nil
   335  	}
   336  }
   337  
   338  // Finalize runs any post-transaction state modifications (e.g. block rewards)
   339  // and assembles the final block.
   340  //
   341  // Note, the block header and state database might be updated to reflect any
   342  // consensus rules that happen at finalization (e.g. block rewards).
   343  func (e *Engine) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {
   344  	// No block rewards in Istanbul, so the state remains as is and uncles are dropped
   345  	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
   346  	header.UncleHash = nilUncleHash
   347  }
   348  
   349  // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
   350  // nor block rewards given, and returns the final block.
   351  func (e *Engine) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
   352  	/// No block rewards in Istanbul, so the state remains as is and uncles are dropped
   353  	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
   354  	header.UncleHash = nilUncleHash
   355  
   356  	// Assemble and return the final block for sealing
   357  	return types.NewBlock(header, txs, nil, receipts, new(trie.Trie)), nil
   358  }
   359  
   360  // Seal generates a new block for the given input block with the local miner's
   361  // seal place on top.
   362  func (e *Engine) Seal(chain consensus.ChainHeaderReader, block *types.Block, validators istanbul.ValidatorSet) (*types.Block, error) {
   363  	if _, v := validators.GetByAddress(e.signer); v == nil {
   364  		return block, istanbulcommon.ErrUnauthorized
   365  	}
   366  
   367  	header := block.Header()
   368  	parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
   369  	if parent == nil {
   370  		return block, consensus.ErrUnknownAncestor
   371  	}
   372  
   373  	// Set Coinbase
   374  	header.Coinbase = e.signer
   375  
   376  	return block.WithSeal(header), nil
   377  }
   378  
   379  func (e *Engine) SealHash(header *types.Header) common.Hash {
   380  	header.Coinbase = e.signer
   381  	return sigHash(header)
   382  }
   383  
   384  func (e *Engine) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int {
   385  	return new(big.Int)
   386  }
   387  
   388  func (e *Engine) Validators(header *types.Header) ([]common.Address, error) {
   389  	extra, err := types.ExtractQBFTExtra(header)
   390  	if err != nil {
   391  		return nil, err
   392  	}
   393  
   394  	return extra.Validators, nil
   395  }
   396  
   397  func (e *Engine) Signers(header *types.Header) ([]common.Address, error) {
   398  	extra, err := types.ExtractQBFTExtra(header)
   399  	if err != nil {
   400  		return []common.Address{}, err
   401  	}
   402  	committedSeal := extra.CommittedSeal
   403  	proposalSeal := PrepareCommittedSeal(header, extra.Round)
   404  
   405  	var addrs []common.Address
   406  	// 1. Get committed seals from current header
   407  	for _, seal := range committedSeal {
   408  		// 2. Get the original address by seal and parent block hash
   409  		addr, err := istanbul.GetSignatureAddressNoHashing(proposalSeal, seal)
   410  		if err != nil {
   411  			return nil, istanbulcommon.ErrInvalidSignature
   412  		}
   413  		addrs = append(addrs, addr)
   414  	}
   415  
   416  	return addrs, nil
   417  }
   418  
   419  func (e *Engine) Address() common.Address {
   420  	return e.signer
   421  }
   422  
   423  // FIXME: Need to update this for Istanbul
   424  // sigHash returns the hash which is used as input for the Istanbul
   425  // signing. It is the hash of the entire header apart from the 65 byte signature
   426  // contained at the end of the extra data.
   427  //
   428  // Note, the method requires the extra data to be at least 65 bytes, otherwise it
   429  // panics. This is done to avoid accidentally using both forms (signature present
   430  // or not), which could be abused to produce different hashes for the same header.
   431  func sigHash(header *types.Header) (hash common.Hash) {
   432  	hasher := sha3.NewLegacyKeccak256()
   433  	rlp.Encode(hasher, types.QBFTFilteredHeader(header))
   434  	hasher.Sum(hash[:0])
   435  	return hash
   436  }
   437  
   438  // PrepareCommittedSeal returns a committed seal for the given hash
   439  func PrepareCommittedSeal(header *types.Header, round uint32) []byte {
   440  	h := types.CopyHeader(header)
   441  	return h.QBFTHashWithRoundNumber(round).Bytes()
   442  }
   443  
   444  func (e *Engine) WriteVote(header *types.Header, candidate common.Address, authorize bool) error {
   445  	return ApplyHeaderQBFTExtra(
   446  		header,
   447  		WriteVote(candidate, authorize),
   448  	)
   449  }
   450  
   451  func WriteVote(candidate common.Address, authorize bool) ApplyQBFTExtra {
   452  	return func(qbftExtra *types.QBFTExtra) error {
   453  		voteType := types.QBFTDropVote
   454  		if authorize {
   455  			voteType = types.QBFTAuthVote
   456  		}
   457  
   458  		vote := &types.ValidatorVote{RecipientAddress: candidate, VoteType: voteType}
   459  		qbftExtra.Vote = vote
   460  		return nil
   461  	}
   462  }
   463  
   464  func (e *Engine) ReadVote(header *types.Header) (candidate common.Address, authorize bool, err error) {
   465  	qbftExtra, err := getExtra(header)
   466  	if err != nil {
   467  		return common.Address{}, false, err
   468  	}
   469  
   470  	var vote *types.ValidatorVote
   471  	if qbftExtra.Vote == nil {
   472  		vote = &types.ValidatorVote{RecipientAddress: common.Address{}, VoteType: types.QBFTDropVote}
   473  	} else {
   474  		vote = qbftExtra.Vote
   475  	}
   476  
   477  	// Tally up the new vote from the validator
   478  	switch {
   479  	case vote.VoteType == types.QBFTAuthVote:
   480  		authorize = true
   481  	case vote.VoteType == types.QBFTDropVote:
   482  		authorize = false
   483  	default:
   484  		return common.Address{}, false, istanbulcommon.ErrInvalidVote
   485  	}
   486  
   487  	return vote.RecipientAddress, authorize, nil
   488  }
   489  
   490  func getExtra(header *types.Header) (*types.QBFTExtra, error) {
   491  	if len(header.Extra) < types.IstanbulExtraVanity {
   492  		// In this scenario, the header extradata only contains client specific information, hence create a new qbftExtra and set vanity
   493  		vanity := append(header.Extra, bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity-len(header.Extra))...)
   494  		return &types.QBFTExtra{
   495  			VanityData:    vanity,
   496  			Validators:    []common.Address{},
   497  			CommittedSeal: [][]byte{},
   498  			Round:         0,
   499  			Vote:          nil,
   500  		}, nil
   501  	}
   502  
   503  	// This is the case when Extra has already been set
   504  	return types.ExtractQBFTExtra(header)
   505  }
   506  
   507  func setExtra(h *types.Header, qbftExtra *types.QBFTExtra) error {
   508  	payload, err := rlp.EncodeToBytes(qbftExtra)
   509  	if err != nil {
   510  		return err
   511  	}
   512  
   513  	h.Extra = payload
   514  	return nil
   515  }