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