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