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

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