github.com/theQRL/go-zond@v0.2.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  	"time"
    24  
    25  	"github.com/theQRL/go-zond/common"
    26  	"github.com/theQRL/go-zond/consensus"
    27  	"github.com/theQRL/go-zond/consensus/misc/eip1559"
    28  	"github.com/theQRL/go-zond/core/state"
    29  	"github.com/theQRL/go-zond/core/types"
    30  	"github.com/theQRL/go-zond/params"
    31  	"github.com/theQRL/go-zond/rpc"
    32  	"github.com/theQRL/go-zond/trie"
    33  )
    34  
    35  // Various error messages to mark blocks invalid. These should be private to
    36  // prevent engine specific errors from being referenced in the remainder of the
    37  // codebase, inherently breaking if the engine is swapped out. Please put common
    38  // error types into the consensus package.
    39  var (
    40  	errInvalidTimestamp = errors.New("invalid timestamp")
    41  )
    42  
    43  // Beacon is a consensus engine that uses the proof-of-stake algorithm.
    44  type Beacon struct {
    45  	fakeFail  *uint64        // Block number which fails PoW check even in fake mode
    46  	fakeDelay *time.Duration // Time delay to sleep for before returning from verify
    47  	fakeFull  bool           // Accepts everything as valid
    48  }
    49  
    50  // New creates a consensus engine.
    51  func New() *Beacon {
    52  	return &Beacon{}
    53  }
    54  
    55  func NewFaker() *Beacon {
    56  	return new(Beacon)
    57  }
    58  
    59  func NewFakeFailer(fail uint64) *Beacon {
    60  	return &Beacon{
    61  		fakeFail: &fail,
    62  	}
    63  }
    64  
    65  func NewFakeDelayer(delay time.Duration) *Beacon {
    66  	return &Beacon{
    67  		fakeDelay: &delay,
    68  	}
    69  }
    70  
    71  func NewFullFaker() *Beacon {
    72  	return &Beacon{
    73  		fakeFull: true,
    74  	}
    75  }
    76  
    77  // Author implements consensus.Engine, returning the verified author of the block.
    78  func (beacon *Beacon) Author(header *types.Header) (common.Address, error) {
    79  	return header.Coinbase, nil
    80  }
    81  
    82  // VerifyHeader checks whether a header conforms to the consensus rules of the
    83  // stock Zond consensus engine.
    84  func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error {
    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  
    91  	// Sanity checks passed, do a proper verification
    92  	return beacon.verifyHeader(chain, header, parent)
    93  }
    94  
    95  // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
    96  // concurrently. The method returns a quit channel to abort the operations and
    97  // a results channel to retrieve the async verifications.
    98  // VerifyHeaders expect the headers to be ordered and continuous.
    99  func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) (chan<- struct{}, <-chan error) {
   100  	return beacon.verifyHeaders(chain, headers, nil)
   101  }
   102  
   103  // verifyHeader checks whether a header conforms to the consensus rules of the
   104  // stock Zond consensus engine. The difference between the beacon and classic is
   105  // (a) The following fields are expected to be constants:
   106  //
   107  //	to be the desired constants
   108  //
   109  // (b) we don't verify if a block is in the future anymore
   110  // (c) the extradata is limited to 32 bytes
   111  func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header) error {
   112  	// Ensure that the header's extra-data section is of a reasonable size
   113  	if len(header.Extra) > 32 {
   114  		return fmt.Errorf("extra-data longer than 32 bytes (%d)", len(header.Extra))
   115  	}
   116  	// Verify the timestamp
   117  	if header.Time <= parent.Time {
   118  		return errInvalidTimestamp
   119  	}
   120  	// Verify that the gas limit is <= 2^63-1
   121  	if header.GasLimit > params.MaxGasLimit {
   122  		return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit)
   123  	}
   124  	// Verify that the gasUsed is <= gasLimit
   125  	if header.GasUsed > header.GasLimit {
   126  		return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
   127  	}
   128  	// Verify that the block number is parent's +1
   129  	if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(common.Big1) != 0 {
   130  		return consensus.ErrInvalidNumber
   131  	}
   132  	// Verify the header's EIP-1559 attributes.
   133  	if err := eip1559.VerifyEIP1559Header(chain.Config(), parent, header); err != nil {
   134  		return err
   135  	}
   136  	// Verify existence / non-existence of withdrawalsHash.
   137  	if header.WithdrawalsHash == nil {
   138  		return errors.New("missing withdrawalsHash")
   139  	}
   140  
   141  	if beacon.fakeDelay != nil {
   142  		time.Sleep(*beacon.fakeDelay)
   143  	}
   144  	if beacon.fakeFail != nil && *beacon.fakeFail == header.Number.Uint64() {
   145  		return errors.New("invalid tester pos")
   146  	}
   147  
   148  	return 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. An additional parent
   154  // header will be passed if the relevant header is not in the database yet.
   155  func (beacon *Beacon) verifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, ancestor *types.Header) (chan<- struct{}, <-chan error) {
   156  	var (
   157  		abort   = make(chan struct{})
   158  		results = make(chan error, len(headers))
   159  	)
   160  	if beacon.fakeFull || len(headers) == 0 {
   161  		for i := 0; i < len(headers); i++ {
   162  			results <- nil
   163  		}
   164  		return abort, results
   165  	}
   166  	go func() {
   167  		for i, header := range headers {
   168  			var parent *types.Header
   169  			if i == 0 {
   170  				if ancestor != nil {
   171  					parent = ancestor
   172  				} else {
   173  					parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1)
   174  				}
   175  			} else if headers[i-1].Hash() == headers[i].ParentHash {
   176  				parent = headers[i-1]
   177  			}
   178  			if parent == nil {
   179  				select {
   180  				case <-abort:
   181  					return
   182  				case results <- consensus.ErrUnknownAncestor:
   183  				}
   184  				continue
   185  			}
   186  			err := beacon.verifyHeader(chain, header, parent)
   187  			select {
   188  			case <-abort:
   189  				return
   190  			case results <- err:
   191  			}
   192  		}
   193  	}()
   194  	return abort, results
   195  }
   196  
   197  // Finalize implements consensus.Engine and processes withdrawals on top.
   198  func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) {
   199  	// Withdrawals processing.
   200  	for _, w := range body.Withdrawals {
   201  		// Convert amount from gwei to wei.
   202  		amount := new(big.Int).SetUint64(w.Amount)
   203  		amount = amount.Mul(amount, big.NewInt(params.GWei))
   204  		state.AddBalance(w.Address, amount)
   205  	}
   206  	// No block reward which is issued by consensus layer instead.
   207  }
   208  
   209  // FinalizeAndAssemble implements consensus.Engine, setting the final state and
   210  // assembling the block.
   211  func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
   212  	// All blocks after Shanghai must include a withdrawals root.
   213  	if body.Withdrawals == nil {
   214  		body.Withdrawals = make([]*types.Withdrawal, 0)
   215  	}
   216  	// Finalize and assemble the block.
   217  	beacon.Finalize(chain, header, state, body)
   218  
   219  	// Assign the final state root to header.
   220  	header.Root = state.IntermediateRoot(true)
   221  
   222  	// Assemble and return the final block.
   223  	return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil
   224  }
   225  
   226  // APIs implements consensus.Engine, returning the user facing RPC APIs.
   227  func (beacon *Beacon) APIs(chain consensus.ChainHeaderReader) []rpc.API {
   228  	return []rpc.API{}
   229  }
   230  
   231  // Close shutdowns the consensus engine
   232  func (beacon *Beacon) Close() error {
   233  	return nil
   234  }