github.com/aiyaya188/klaytn@v0.0.0-20220629133911-2c66fd5546f4/consensus/beacon/consensus.go (about)

     1  // Copyright 2021 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 beacon
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"math/big"
    23  
    24  	"github.com/aiyaya188/klaytn/common"
    25  	"github.com/aiyaya188/klaytn/consensus"
    26  	"github.com/aiyaya188/klaytn/consensus/misc"
    27  	"github.com/aiyaya188/klaytn/core/state"
    28  	"github.com/aiyaya188/klaytn/core/types"
    29  	"github.com/aiyaya188/klaytn/params"
    30  	"github.com/aiyaya188/klaytn/rpc"
    31  	"github.com/aiyaya188/klaytn/trie"
    32  )
    33  
    34  // Proof-of-stake protocol constants.
    35  var (
    36  	beaconDifficulty = common.Big0          // The default block difficulty in the beacon consensus
    37  	beaconNonce      = types.EncodeNonce(0) // The default block nonce in the beacon consensus
    38  )
    39  
    40  // Various error messages to mark blocks invalid. These should be private to
    41  // prevent engine specific errors from being referenced in the remainder of the
    42  // codebase, inherently breaking if the engine is swapped out. Please put common
    43  // error types into the consensus package.
    44  var (
    45  	errTooManyUncles    = errors.New("too many uncles")
    46  	errInvalidNonce     = errors.New("invalid nonce")
    47  	errInvalidUncleHash = errors.New("invalid uncle hash")
    48  )
    49  
    50  // Beacon is a consensus engine that combines the eth1 consensus and proof-of-stake
    51  // algorithm. There is a special flag inside to decide whether to use legacy consensus
    52  // rules or new rules. The transition rule is described in the eth1/2 merge spec.
    53  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3675.md
    54  //
    55  // The beacon here is a half-functional consensus engine with partial functions which
    56  // is only used for necessary consensus checks. The legacy consensus engine can be any
    57  // engine implements the consensus interface (except the beacon itself).
    58  type Beacon struct {
    59  	ethone consensus.Engine // Original consensus engine used in eth1, e.g. ethash or clique
    60  }
    61  
    62  // New creates a consensus engine with the given embedded eth1 engine.
    63  func New(ethone consensus.Engine) *Beacon {
    64  	if _, ok := ethone.(*Beacon); ok {
    65  		panic("nested consensus engine")
    66  	}
    67  	return &Beacon{ethone: ethone}
    68  }
    69  
    70  // Author implements consensus.Engine, returning the verified author of the block.
    71  func (beacon *Beacon) Author(header *types.Header) (common.Address, error) {
    72  	if !beacon.IsPoSHeader(header) {
    73  		return beacon.ethone.Author(header)
    74  	}
    75  	return header.Coinbase, nil
    76  }
    77  
    78  // VerifyHeader checks whether a header conforms to the consensus rules of the
    79  // stock Ethereum consensus engine.
    80  func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error {
    81  	reached, _ := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1)
    82  	if !reached {
    83  		return beacon.ethone.VerifyHeader(chain, header, seal)
    84  	}
    85  	// Short circuit if the parent is not known
    86  	parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
    87  	if parent == nil {
    88  		return consensus.ErrUnknownAncestor
    89  	}
    90  	// Sanity checks passed, do a proper verification
    91  	return beacon.verifyHeader(chain, header, parent)
    92  }
    93  
    94  // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
    95  // concurrently. The method returns a quit channel to abort the operations and
    96  // a results channel to retrieve the async verifications.
    97  // VerifyHeaders expect the headers to be ordered and continuous.
    98  func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
    99  	if !beacon.IsPoSHeader(headers[len(headers)-1]) {
   100  		return beacon.ethone.VerifyHeaders(chain, headers, seals)
   101  	}
   102  	var (
   103  		preHeaders  []*types.Header
   104  		postHeaders []*types.Header
   105  		preSeals    []bool
   106  	)
   107  	for index, header := range headers {
   108  		if beacon.IsPoSHeader(header) {
   109  			preHeaders = headers[:index]
   110  			postHeaders = headers[index:]
   111  			preSeals = seals[:index]
   112  			break
   113  		}
   114  	}
   115  
   116  	// All the headers have passed the transition point, use new rules.
   117  	if len(preHeaders) == 0 {
   118  		return beacon.verifyHeaders(chain, headers, nil)
   119  	}
   120  
   121  	// The transition point exists in the middle, separate the headers
   122  	// into two batches and apply different verification rules for them.
   123  	var (
   124  		abort   = make(chan struct{})
   125  		results = make(chan error, len(headers))
   126  	)
   127  	go func() {
   128  		var (
   129  			old, new, out      = 0, len(preHeaders), 0
   130  			errors             = make([]error, len(headers))
   131  			done               = make([]bool, len(headers))
   132  			oldDone, oldResult = beacon.ethone.VerifyHeaders(chain, preHeaders, preSeals)
   133  			newDone, newResult = beacon.verifyHeaders(chain, postHeaders, preHeaders[len(preHeaders)-1])
   134  		)
   135  		// Verify that pre-merge headers don't overflow the TTD
   136  		if index, err := verifyTerminalPoWBlock(chain, preHeaders); err != nil {
   137  			// Mark all subsequent pow headers with the error.
   138  			for i := index; i < len(preHeaders); i++ {
   139  				errors[i], done[i] = err, true
   140  			}
   141  		}
   142  		// Collect the results
   143  		for {
   144  			for ; done[out]; out++ {
   145  				results <- errors[out]
   146  				if out == len(headers)-1 {
   147  					return
   148  				}
   149  			}
   150  			select {
   151  			case err := <-oldResult:
   152  				if !done[old] { // skip TTD-verified failures
   153  					errors[old], done[old] = err, true
   154  				}
   155  				old++
   156  			case err := <-newResult:
   157  				errors[new], done[new] = err, true
   158  				new++
   159  			case <-abort:
   160  				close(oldDone)
   161  				close(newDone)
   162  				return
   163  			}
   164  		}
   165  	}()
   166  	return abort, results
   167  }
   168  
   169  // verifyTerminalPoWBlock verifies that the preHeaders confirm to the specification
   170  // wrt. their total difficulty.
   171  // It expects:
   172  // - preHeaders to be at least 1 element
   173  // - the parent of the header element to be stored in the chain correctly
   174  // - the preHeaders to have a set difficulty
   175  // - the last element to be the terminal block
   176  func verifyTerminalPoWBlock(chain consensus.ChainHeaderReader, preHeaders []*types.Header) (int, error) {
   177  	td := chain.GetTd(preHeaders[0].ParentHash, preHeaders[0].Number.Uint64()-1)
   178  	if td == nil {
   179  		return 0, consensus.ErrUnknownAncestor
   180  	}
   181  	// Check that all blocks before the last one are below the TTD
   182  	for i, head := range preHeaders {
   183  		if td.Cmp(chain.Config().TerminalTotalDifficulty) >= 0 {
   184  			return i, consensus.ErrInvalidTerminalBlock
   185  		}
   186  		td.Add(td, head.Difficulty)
   187  	}
   188  	// Check that the last block is the terminal block
   189  	if td.Cmp(chain.Config().TerminalTotalDifficulty) < 0 {
   190  		return len(preHeaders) - 1, consensus.ErrInvalidTerminalBlock
   191  	}
   192  	return 0, nil
   193  }
   194  
   195  // VerifyUncles verifies that the given block's uncles conform to the consensus
   196  // rules of the Ethereum consensus engine.
   197  func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
   198  	if !beacon.IsPoSHeader(block.Header()) {
   199  		return beacon.ethone.VerifyUncles(chain, block)
   200  	}
   201  	// Verify that there is no uncle block. It's explicitly disabled in the beacon
   202  	if len(block.Uncles()) > 0 {
   203  		return errTooManyUncles
   204  	}
   205  	return nil
   206  }
   207  
   208  // verifyHeader checks whether a header conforms to the consensus rules of the
   209  // stock Ethereum consensus engine. The difference between the beacon and classic is
   210  // (a) The following fields are expected to be constants:
   211  //     - difficulty is expected to be 0
   212  // 	   - nonce is expected to be 0
   213  //     - unclehash is expected to be Hash(emptyHeader)
   214  //     to be the desired constants
   215  // (b) the timestamp is not verified anymore
   216  // (c) the extradata is limited to 32 bytes
   217  func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header) error {
   218  	// Ensure that the header's extra-data section is of a reasonable size
   219  	if len(header.Extra) > 32 {
   220  		return fmt.Errorf("extra-data longer than 32 bytes (%d)", len(header.Extra))
   221  	}
   222  	// Verify the seal parts. Ensure the nonce and uncle hash are the expected value.
   223  	if header.Nonce != beaconNonce {
   224  		return errInvalidNonce
   225  	}
   226  	if header.UncleHash != types.EmptyUncleHash {
   227  		return errInvalidUncleHash
   228  	}
   229  	// Verify the block's difficulty to ensure it's the default constant
   230  	if beaconDifficulty.Cmp(header.Difficulty) != 0 {
   231  		return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, beaconDifficulty)
   232  	}
   233  	// Verify that the gas limit is <= 2^63-1
   234  	if header.GasLimit > params.MaxGasLimit {
   235  		return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit)
   236  	}
   237  	// Verify that the gasUsed is <= gasLimit
   238  	if header.GasUsed > header.GasLimit {
   239  		return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
   240  	}
   241  	// Verify that the block number is parent's +1
   242  	if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(common.Big1) != 0 {
   243  		return consensus.ErrInvalidNumber
   244  	}
   245  	// Verify the header's EIP-1559 attributes.
   246  	return misc.VerifyEip1559Header(chain.Config(), parent, header)
   247  }
   248  
   249  // verifyHeaders is similar to verifyHeader, but verifies a batch of headers
   250  // concurrently. The method returns a quit channel to abort the operations and
   251  // a results channel to retrieve the async verifications. An additional parent
   252  // header will be passed if the relevant header is not in the database yet.
   253  func (beacon *Beacon) verifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, ancestor *types.Header) (chan<- struct{}, <-chan error) {
   254  	var (
   255  		abort   = make(chan struct{})
   256  		results = make(chan error, len(headers))
   257  	)
   258  	go func() {
   259  		for i, header := range headers {
   260  			var parent *types.Header
   261  			if i == 0 {
   262  				if ancestor != nil {
   263  					parent = ancestor
   264  				} else {
   265  					parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1)
   266  				}
   267  			} else if headers[i-1].Hash() == headers[i].ParentHash {
   268  				parent = headers[i-1]
   269  			}
   270  			if parent == nil {
   271  				select {
   272  				case <-abort:
   273  					return
   274  				case results <- consensus.ErrUnknownAncestor:
   275  				}
   276  				continue
   277  			}
   278  			err := beacon.verifyHeader(chain, header, parent)
   279  			select {
   280  			case <-abort:
   281  				return
   282  			case results <- err:
   283  			}
   284  		}
   285  	}()
   286  	return abort, results
   287  }
   288  
   289  // Prepare implements consensus.Engine, initializing the difficulty field of a
   290  // header to conform to the beacon protocol. The changes are done inline.
   291  func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
   292  	// Transition isn't triggered yet, use the legacy rules for preparation.
   293  	reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1)
   294  	if err != nil {
   295  		return err
   296  	}
   297  	if !reached {
   298  		return beacon.ethone.Prepare(chain, header)
   299  	}
   300  	header.Difficulty = beaconDifficulty
   301  	return nil
   302  }
   303  
   304  // Finalize implements consensus.Engine, setting the final state on the header
   305  func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {
   306  	// Finalize is different with Prepare, it can be used in both block generation
   307  	// and verification. So determine the consensus rules by header type.
   308  	if !beacon.IsPoSHeader(header) {
   309  		beacon.ethone.Finalize(chain, header, state, txs, uncles)
   310  		return
   311  	}
   312  	// The block reward is no longer handled here. It's done by the
   313  	// external consensus engine.
   314  	header.Root = state.IntermediateRoot(true)
   315  }
   316  
   317  // FinalizeAndAssemble implements consensus.Engine, setting the final state and
   318  // assembling the block.
   319  func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
   320  	// FinalizeAndAssemble is different with Prepare, it can be used in both block
   321  	// generation and verification. So determine the consensus rules by header type.
   322  	if !beacon.IsPoSHeader(header) {
   323  		return beacon.ethone.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts)
   324  	}
   325  	// Finalize and assemble the block
   326  	beacon.Finalize(chain, header, state, txs, uncles)
   327  	return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil
   328  }
   329  
   330  // Seal generates a new sealing request for the given input block and pushes
   331  // the result into the given channel.
   332  //
   333  // Note, the method returns immediately and will send the result async. More
   334  // than one result may also be returned depending on the consensus algorithm.
   335  func (beacon *Beacon) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
   336  	if !beacon.IsPoSHeader(block.Header()) {
   337  		return beacon.ethone.Seal(chain, block, results, stop)
   338  	}
   339  	// The seal verification is done by the external consensus engine,
   340  	// return directly without pushing any block back. In another word
   341  	// beacon won't return any result by `results` channel which may
   342  	// blocks the receiver logic forever.
   343  	return nil
   344  }
   345  
   346  // SealHash returns the hash of a block prior to it being sealed.
   347  func (beacon *Beacon) SealHash(header *types.Header) common.Hash {
   348  	return beacon.ethone.SealHash(header)
   349  }
   350  
   351  // CalcDifficulty is the difficulty adjustment algorithm. It returns
   352  // the difficulty that a new block should have when created at time
   353  // given the parent block's time and difficulty.
   354  func (beacon *Beacon) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int {
   355  	// Transition isn't triggered yet, use the legacy rules for calculation
   356  	if reached, _ := IsTTDReached(chain, parent.Hash(), parent.Number.Uint64()); !reached {
   357  		return beacon.ethone.CalcDifficulty(chain, time, parent)
   358  	}
   359  	return beaconDifficulty
   360  }
   361  
   362  // APIs implements consensus.Engine, returning the user facing RPC APIs.
   363  func (beacon *Beacon) APIs(chain consensus.ChainHeaderReader) []rpc.API {
   364  	return beacon.ethone.APIs(chain)
   365  }
   366  
   367  // Close shutdowns the consensus engine
   368  func (beacon *Beacon) Close() error {
   369  	return beacon.ethone.Close()
   370  }
   371  
   372  // IsPoSHeader reports the header belongs to the PoS-stage with some special fields.
   373  // This function is not suitable for a part of APIs like Prepare or CalcDifficulty
   374  // because the header difficulty is not set yet.
   375  func (beacon *Beacon) IsPoSHeader(header *types.Header) bool {
   376  	if header.Difficulty == nil {
   377  		panic("IsPoSHeader called with invalid difficulty")
   378  	}
   379  	return header.Difficulty.Cmp(beaconDifficulty) == 0
   380  }
   381  
   382  // InnerEngine returns the embedded eth1 consensus engine.
   383  func (beacon *Beacon) InnerEngine() consensus.Engine {
   384  	return beacon.ethone
   385  }
   386  
   387  // SetThreads updates the mining threads. Delegate the call
   388  // to the eth1 engine if it's threaded.
   389  func (beacon *Beacon) SetThreads(threads int) {
   390  	type threaded interface {
   391  		SetThreads(threads int)
   392  	}
   393  	if th, ok := beacon.ethone.(threaded); ok {
   394  		th.SetThreads(threads)
   395  	}
   396  }
   397  
   398  // IsTTDReached checks if the TotalTerminalDifficulty has been surpassed on the `parentHash` block.
   399  // It depends on the parentHash already being stored in the database.
   400  // If the parentHash is not stored in the database a UnknownAncestor error is returned.
   401  func IsTTDReached(chain consensus.ChainHeaderReader, parentHash common.Hash, number uint64) (bool, error) {
   402  	if chain.Config().TerminalTotalDifficulty == nil {
   403  		return false, nil
   404  	}
   405  	td := chain.GetTd(parentHash, number)
   406  	if td == nil {
   407  		return false, consensus.ErrUnknownAncestor
   408  	}
   409  	return td.Cmp(chain.Config().TerminalTotalDifficulty) >= 0, nil
   410  }