github.com/ethereum/go-ethereum@v1.16.1/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/core/vm"
    32  	"github.com/ethereum/go-ethereum/params"
    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  // isPostMerge reports whether the given block number is assumed to be post-merge.
    75  // Here we check the MergeNetsplitBlock to allow configuring networks with a PoW or
    76  // PoA chain for unit testing purposes.
    77  func isPostMerge(config *params.ChainConfig, blockNum uint64, timestamp uint64) bool {
    78  	mergedAtGenesis := config.TerminalTotalDifficulty != nil && config.TerminalTotalDifficulty.Sign() == 0
    79  	return mergedAtGenesis ||
    80  		config.MergeNetsplitBlock != nil && blockNum >= config.MergeNetsplitBlock.Uint64() ||
    81  		config.ShanghaiTime != nil && timestamp >= *config.ShanghaiTime
    82  }
    83  
    84  // Author implements consensus.Engine, returning the verified author of the block.
    85  func (beacon *Beacon) Author(header *types.Header) (common.Address, error) {
    86  	if !beacon.IsPoSHeader(header) {
    87  		return beacon.ethone.Author(header)
    88  	}
    89  	return header.Coinbase, nil
    90  }
    91  
    92  // VerifyHeader checks whether a header conforms to the consensus rules of the
    93  // stock Ethereum consensus engine.
    94  func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error {
    95  	// During the live merge transition, the consensus engine used the terminal
    96  	// total difficulty to detect when PoW (PoA) switched to PoS. Maintaining the
    97  	// total difficulty values however require applying all the blocks from the
    98  	// genesis to build up the TD. This stops being a possibility if the tail of
    99  	// the chain is pruned already during sync.
   100  	//
   101  	// One heuristic that can be used to distinguish pre-merge and post-merge
   102  	// blocks is whether their *difficulty* is >0 or ==0 respectively. This of
   103  	// course would mean that we cannot prove anymore for a past chain that it
   104  	// truly transitioned at the correct TTD, but if we consider that ancient
   105  	// point in time finalized a long time ago, there should be no attempt from
   106  	// the consensus client to rewrite very old history.
   107  	//
   108  	// One thing that's probably not needed but which we can add to make this
   109  	// verification even stricter is to enforce that the chain can switch from
   110  	// >0 to ==0 TD only once by forbidding an ==0 to be followed by a >0.
   111  
   112  	// Verify that we're not reverting to pre-merge from post-merge
   113  	parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
   114  	if parent == nil {
   115  		return consensus.ErrUnknownAncestor
   116  	}
   117  	if parent.Difficulty.Sign() == 0 && header.Difficulty.Sign() > 0 {
   118  		return consensus.ErrInvalidTerminalBlock
   119  	}
   120  	// Check >0 TDs with pre-merge, --0 TDs with post-merge rules
   121  	if header.Difficulty.Sign() > 0 {
   122  		return beacon.ethone.VerifyHeader(chain, header)
   123  	}
   124  	return beacon.verifyHeader(chain, header, parent)
   125  }
   126  
   127  // splitHeaders splits the provided header batch into two parts according to
   128  // the difficulty field.
   129  //
   130  // Note, this function will not verify the header validity but just split them.
   131  func (beacon *Beacon) splitHeaders(headers []*types.Header) ([]*types.Header, []*types.Header) {
   132  	var (
   133  		preHeaders  = headers
   134  		postHeaders []*types.Header
   135  	)
   136  	for i, header := range headers {
   137  		if header.Difficulty.Sign() == 0 {
   138  			preHeaders = headers[:i]
   139  			postHeaders = headers[i:]
   140  			break
   141  		}
   142  	}
   143  	return preHeaders, postHeaders
   144  }
   145  
   146  // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
   147  // concurrently. The method returns a quit channel to abort the operations and
   148  // a results channel to retrieve the async verifications.
   149  // VerifyHeaders expect the headers to be ordered and continuous.
   150  func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) (chan<- struct{}, <-chan error) {
   151  	preHeaders, postHeaders := beacon.splitHeaders(headers)
   152  	if len(postHeaders) == 0 {
   153  		return beacon.ethone.VerifyHeaders(chain, headers)
   154  	}
   155  	if len(preHeaders) == 0 {
   156  		return beacon.verifyHeaders(chain, headers, nil)
   157  	}
   158  	// The transition point exists in the middle, separate the headers
   159  	// into two batches and apply different verification rules for them.
   160  	var (
   161  		abort   = make(chan struct{})
   162  		results = make(chan error, len(headers))
   163  	)
   164  	go func() {
   165  		var (
   166  			old, new, out      = 0, len(preHeaders), 0
   167  			errors             = make([]error, len(headers))
   168  			done               = make([]bool, len(headers))
   169  			oldDone, oldResult = beacon.ethone.VerifyHeaders(chain, preHeaders)
   170  			newDone, newResult = beacon.verifyHeaders(chain, postHeaders, preHeaders[len(preHeaders)-1])
   171  		)
   172  		// Collect the results
   173  		for {
   174  			for ; done[out]; out++ {
   175  				results <- errors[out]
   176  				if out == len(headers)-1 {
   177  					return
   178  				}
   179  			}
   180  			select {
   181  			case err := <-oldResult:
   182  				if !done[old] { // skip TTD-verified failures
   183  					errors[old], done[old] = err, true
   184  				}
   185  				old++
   186  			case err := <-newResult:
   187  				errors[new], done[new] = err, true
   188  				new++
   189  			case <-abort:
   190  				close(oldDone)
   191  				close(newDone)
   192  				return
   193  			}
   194  		}
   195  	}()
   196  	return abort, results
   197  }
   198  
   199  // VerifyUncles verifies that the given block's uncles conform to the consensus
   200  // rules of the Ethereum consensus engine.
   201  func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
   202  	if !beacon.IsPoSHeader(block.Header()) {
   203  		return beacon.ethone.VerifyUncles(chain, block)
   204  	}
   205  	// Verify that there is no uncle block. It's explicitly disabled in the beacon
   206  	if len(block.Uncles()) > 0 {
   207  		return errTooManyUncles
   208  	}
   209  	return nil
   210  }
   211  
   212  // verifyHeader checks whether a header conforms to the consensus rules of the
   213  // stock Ethereum consensus engine. The difference between the beacon and classic is
   214  // (a) The following fields are expected to be constants:
   215  //   - difficulty is expected to be 0
   216  //   - nonce is expected to be 0
   217  //   - unclehash is expected to be Hash(emptyHeader)
   218  //     to be the desired constants
   219  //
   220  // (b) we don't verify if a block is in the future anymore
   221  // (c) the extradata is limited to 32 bytes
   222  func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header) error {
   223  	// Ensure that the header's extra-data section is of a reasonable size
   224  	if len(header.Extra) > int(params.MaximumExtraDataSize) {
   225  		return fmt.Errorf("extra-data longer than 32 bytes (%d)", len(header.Extra))
   226  	}
   227  	// Verify the seal parts. Ensure the nonce and uncle hash are the expected value.
   228  	if header.Nonce != beaconNonce {
   229  		return errInvalidNonce
   230  	}
   231  	if header.UncleHash != types.EmptyUncleHash {
   232  		return errInvalidUncleHash
   233  	}
   234  	// Verify the timestamp
   235  	if header.Time <= parent.Time {
   236  		return errInvalidTimestamp
   237  	}
   238  	// Verify the block's difficulty to ensure it's the default constant
   239  	if beaconDifficulty.Cmp(header.Difficulty) != 0 {
   240  		return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, beaconDifficulty)
   241  	}
   242  	// Verify that the gas limit is <= 2^63-1
   243  	if header.GasLimit > params.MaxGasLimit {
   244  		return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit)
   245  	}
   246  	// Verify that the gasUsed is <= gasLimit
   247  	if header.GasUsed > header.GasLimit {
   248  		return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
   249  	}
   250  	// Verify that the block number is parent's +1
   251  	if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(common.Big1) != 0 {
   252  		return consensus.ErrInvalidNumber
   253  	}
   254  	// Verify the header's EIP-1559 attributes.
   255  	if err := eip1559.VerifyEIP1559Header(chain.Config(), parent, header); err != nil {
   256  		return err
   257  	}
   258  	// Verify existence / non-existence of withdrawalsHash.
   259  	shanghai := chain.Config().IsShanghai(header.Number, header.Time)
   260  	if shanghai && header.WithdrawalsHash == nil {
   261  		return errors.New("missing withdrawalsHash")
   262  	}
   263  	if !shanghai && header.WithdrawalsHash != nil {
   264  		return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
   265  	}
   266  	// Verify the existence / non-existence of cancun-specific header fields
   267  	cancun := chain.Config().IsCancun(header.Number, header.Time)
   268  	if !cancun {
   269  		switch {
   270  		case header.ExcessBlobGas != nil:
   271  			return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas)
   272  		case header.BlobGasUsed != nil:
   273  			return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
   274  		case header.ParentBeaconRoot != nil:
   275  			return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
   276  		}
   277  	} else {
   278  		if header.ParentBeaconRoot == nil {
   279  			return errors.New("header is missing beaconRoot")
   280  		}
   281  		if err := eip4844.VerifyEIP4844Header(chain.Config(), parent, header); err != nil {
   282  			return err
   283  		}
   284  	}
   285  	return nil
   286  }
   287  
   288  // verifyHeaders is similar to verifyHeader, but verifies a batch of headers
   289  // concurrently. The method returns a quit channel to abort the operations and
   290  // a results channel to retrieve the async verifications. An additional parent
   291  // header will be passed if the relevant header is not in the database yet.
   292  func (beacon *Beacon) verifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, ancestor *types.Header) (chan<- struct{}, <-chan error) {
   293  	var (
   294  		abort   = make(chan struct{})
   295  		results = make(chan error, len(headers))
   296  	)
   297  	go func() {
   298  		for i, header := range headers {
   299  			var parent *types.Header
   300  			if i == 0 {
   301  				if ancestor != nil {
   302  					parent = ancestor
   303  				} else {
   304  					parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1)
   305  				}
   306  			} else if headers[i-1].Hash() == headers[i].ParentHash {
   307  				parent = headers[i-1]
   308  			}
   309  			if parent == nil {
   310  				select {
   311  				case <-abort:
   312  					return
   313  				case results <- consensus.ErrUnknownAncestor:
   314  				}
   315  				continue
   316  			}
   317  			err := beacon.verifyHeader(chain, header, parent)
   318  			select {
   319  			case <-abort:
   320  				return
   321  			case results <- err:
   322  			}
   323  		}
   324  	}()
   325  	return abort, results
   326  }
   327  
   328  // Prepare implements consensus.Engine, initializing the difficulty field of a
   329  // header to conform to the beacon protocol. The changes are done inline.
   330  func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
   331  	if !isPostMerge(chain.Config(), header.Number.Uint64(), header.Time) {
   332  		return beacon.ethone.Prepare(chain, header)
   333  	}
   334  	header.Difficulty = beaconDifficulty
   335  	return nil
   336  }
   337  
   338  // Finalize implements consensus.Engine and processes withdrawals on top.
   339  func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state vm.StateDB, body *types.Body) {
   340  	if !beacon.IsPoSHeader(header) {
   341  		beacon.ethone.Finalize(chain, header, state, body)
   342  		return
   343  	}
   344  	// Withdrawals processing.
   345  	for _, w := range body.Withdrawals {
   346  		// Convert amount from gwei to wei.
   347  		amount := new(uint256.Int).SetUint64(w.Amount)
   348  		amount = amount.Mul(amount, uint256.NewInt(params.GWei))
   349  		state.AddBalance(w.Address, amount, tracing.BalanceIncreaseWithdrawal)
   350  	}
   351  	// No block reward which is issued by consensus layer instead.
   352  }
   353  
   354  // FinalizeAndAssemble implements consensus.Engine, setting the final state and
   355  // assembling the block.
   356  func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
   357  	if !beacon.IsPoSHeader(header) {
   358  		return beacon.ethone.FinalizeAndAssemble(chain, header, state, body, receipts)
   359  	}
   360  	shanghai := chain.Config().IsShanghai(header.Number, header.Time)
   361  	if shanghai {
   362  		// All blocks after Shanghai must include a withdrawals root.
   363  		if body.Withdrawals == nil {
   364  			body.Withdrawals = make([]*types.Withdrawal, 0)
   365  		}
   366  	} else {
   367  		if len(body.Withdrawals) > 0 {
   368  			return nil, errors.New("withdrawals set before Shanghai activation")
   369  		}
   370  	}
   371  	// Finalize and assemble the block.
   372  	beacon.Finalize(chain, header, state, body)
   373  
   374  	// Assign the final state root to header.
   375  	header.Root = state.IntermediateRoot(true)
   376  
   377  	// Assemble the final block.
   378  	block := types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))
   379  
   380  	// Create the block witness and attach to block.
   381  	// This step needs to happen as late as possible to catch all access events.
   382  	if chain.Config().IsVerkle(header.Number, header.Time) {
   383  		keys := state.AccessEvents().Keys()
   384  
   385  		// Open the pre-tree to prove the pre-state against
   386  		parent := chain.GetHeaderByNumber(header.Number.Uint64() - 1)
   387  		if parent == nil {
   388  			return nil, fmt.Errorf("nil parent header for block %d", header.Number)
   389  		}
   390  		preTrie, err := state.Database().OpenTrie(parent.Root)
   391  		if err != nil {
   392  			return nil, fmt.Errorf("error opening pre-state tree root: %w", err)
   393  		}
   394  		postTrie := state.GetTrie()
   395  		if postTrie == nil {
   396  			return nil, errors.New("post-state tree is not available")
   397  		}
   398  		vktPreTrie, okpre := preTrie.(*trie.VerkleTrie)
   399  		vktPostTrie, okpost := postTrie.(*trie.VerkleTrie)
   400  
   401  		// The witness is only attached iff both parent and current block are
   402  		// using verkle tree.
   403  		if okpre && okpost {
   404  			if len(keys) > 0 {
   405  				verkleProof, stateDiff, err := vktPreTrie.Proof(vktPostTrie, keys)
   406  				if err != nil {
   407  					return nil, fmt.Errorf("error generating verkle proof for block %d: %w", header.Number, err)
   408  				}
   409  				block = block.WithWitness(&types.ExecutionWitness{
   410  					StateDiff:   stateDiff,
   411  					VerkleProof: verkleProof,
   412  				})
   413  			}
   414  		}
   415  	}
   416  
   417  	return block, nil
   418  }
   419  
   420  // Seal generates a new sealing request for the given input block and pushes
   421  // the result into the given channel.
   422  //
   423  // Note, the method returns immediately and will send the result async. More
   424  // than one result may also be returned depending on the consensus algorithm.
   425  func (beacon *Beacon) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
   426  	if !beacon.IsPoSHeader(block.Header()) {
   427  		return beacon.ethone.Seal(chain, block, results, stop)
   428  	}
   429  	// The seal verification is done by the external consensus engine,
   430  	// return directly without pushing any block back. In another word
   431  	// beacon won't return any result by `results` channel which may
   432  	// blocks the receiver logic forever.
   433  	return nil
   434  }
   435  
   436  // SealHash returns the hash of a block prior to it being sealed.
   437  func (beacon *Beacon) SealHash(header *types.Header) common.Hash {
   438  	return beacon.ethone.SealHash(header)
   439  }
   440  
   441  // CalcDifficulty is the difficulty adjustment algorithm. It returns
   442  // the difficulty that a new block should have when created at time
   443  // given the parent block's time and difficulty.
   444  func (beacon *Beacon) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int {
   445  	if !isPostMerge(chain.Config(), parent.Number.Uint64()+1, time) {
   446  		return beacon.ethone.CalcDifficulty(chain, time, parent)
   447  	}
   448  	return beaconDifficulty
   449  }
   450  
   451  // Close shutdowns the consensus engine
   452  func (beacon *Beacon) Close() error {
   453  	return beacon.ethone.Close()
   454  }
   455  
   456  // IsPoSHeader reports the header belongs to the PoS-stage with some special fields.
   457  // This function is not suitable for a part of APIs like Prepare or CalcDifficulty
   458  // because the header difficulty is not set yet.
   459  func (beacon *Beacon) IsPoSHeader(header *types.Header) bool {
   460  	if header.Difficulty == nil {
   461  		panic("IsPoSHeader called with invalid difficulty")
   462  	}
   463  	return header.Difficulty.Cmp(beaconDifficulty) == 0
   464  }
   465  
   466  // InnerEngine returns the embedded eth1 consensus engine.
   467  func (beacon *Beacon) InnerEngine() consensus.Engine {
   468  	return beacon.ethone
   469  }
   470  
   471  // SetThreads updates the mining threads. Delegate the call
   472  // to the eth1 engine if it's threaded.
   473  func (beacon *Beacon) SetThreads(threads int) {
   474  	type threaded interface {
   475  		SetThreads(threads int)
   476  	}
   477  	if th, ok := beacon.ethone.(threaded); ok {
   478  		th.SetThreads(threads)
   479  	}
   480  }