gitlab.com/flarenetwork/coreth@v0.1.1/consensus/dummy/consensus.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package dummy
     5  
     6  import (
     7  	"bytes"
     8  	"errors"
     9  	"fmt"
    10  	"math/big"
    11  	"time"
    12  
    13  	"github.com/ethereum/go-ethereum/common"
    14  	"github.com/ethereum/go-ethereum/trie"
    15  	"gitlab.com/flarenetwork/coreth/consensus"
    16  	"gitlab.com/flarenetwork/coreth/core/state"
    17  	"gitlab.com/flarenetwork/coreth/core/types"
    18  	"gitlab.com/flarenetwork/coreth/params"
    19  	"gitlab.com/flarenetwork/coreth/rpc"
    20  )
    21  
    22  type OnFinalizeCallbackType = func(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, receipts []*types.Receipt, uncles []*types.Header) error
    23  type OnFinalizeAndAssembleCallbackType = func(header *types.Header, state *state.StateDB, txs []*types.Transaction) ([]byte, error)
    24  type OnAPIsCallbackType = func(consensus.ChainHeaderReader) []rpc.API
    25  type OnExtraStateChangeType = func(block *types.Block, statedb *state.StateDB) error
    26  
    27  type ConsensusCallbacks struct {
    28  	OnAPIs                OnAPIsCallbackType
    29  	OnFinalize            OnFinalizeCallbackType
    30  	OnFinalizeAndAssemble OnFinalizeAndAssembleCallbackType
    31  	OnExtraStateChange    OnExtraStateChangeType
    32  }
    33  
    34  type DummyEngine struct {
    35  	cb *ConsensusCallbacks
    36  }
    37  
    38  func NewDummyEngine(cb *ConsensusCallbacks) *DummyEngine {
    39  	return &DummyEngine{
    40  		cb: cb,
    41  	}
    42  }
    43  
    44  func NewFaker() *DummyEngine {
    45  	return NewDummyEngine(new(ConsensusCallbacks))
    46  }
    47  
    48  var (
    49  	allowedFutureBlockTime = 10 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks
    50  )
    51  
    52  var (
    53  	errInvalidBlockTime  = errors.New("timestamp less than parent's")
    54  	errUnclesUnsupported = errors.New("uncles unsupported")
    55  )
    56  
    57  // modified from consensus.go
    58  func (self *DummyEngine) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header, uncle bool) error {
    59  	// Ensure that we do not verify an uncle
    60  	if uncle {
    61  		return errUnclesUnsupported
    62  	}
    63  	// Ensure that the header's extra-data section is of a reasonable size
    64  	if !chain.Config().IsApricotPhase3(new(big.Int).SetUint64(header.Time)) {
    65  		if uint64(len(header.Extra)) > params.MaximumExtraDataSize {
    66  			return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize)
    67  		}
    68  		// Verify BaseFee is not present before EIP-1559
    69  		// Note: this has been moved up from below in order to only switch on IsApricotPhase3 once.
    70  		if header.BaseFee != nil {
    71  			return fmt.Errorf("invalid baseFee before fork: have %d, want <nil>", header.BaseFee)
    72  		}
    73  	} else {
    74  		if len(header.Extra) != params.ApricotPhase3ExtraDataSize {
    75  			return fmt.Errorf("expected extra-data field to be: %d, but found %d", params.ApricotPhase3ExtraDataSize, len(header.Extra))
    76  		}
    77  		// Verify baseFee and rollupWindow encoding as part of header verification
    78  		expectedRollupWindowBytes, expectedBaseFee, err := CalcBaseFee(chain.Config(), parent, header.Time)
    79  		if err != nil {
    80  			return fmt.Errorf("failed to calculate base fee: %w", err)
    81  		}
    82  		if !bytes.Equal(expectedRollupWindowBytes, header.Extra) {
    83  			return fmt.Errorf("expected rollup window bytes: %x, found %x", expectedRollupWindowBytes, header.Extra)
    84  		}
    85  		if header.BaseFee.Cmp(expectedBaseFee) != 0 {
    86  			return fmt.Errorf("expected base fee (%d), found (%d)", expectedBaseFee, header.BaseFee)
    87  		}
    88  	}
    89  
    90  	// Verify the header's timestamp
    91  	if header.Time > uint64(time.Now().Add(allowedFutureBlockTime).Unix()) {
    92  		return consensus.ErrFutureBlock
    93  	}
    94  	//if header.Time <= parent.Time {
    95  	if header.Time < parent.Time {
    96  		return errInvalidBlockTime
    97  	}
    98  	// Verify that the gas limit is <= 2^63-1
    99  	cap := uint64(0x7fffffffffffffff)
   100  	if header.GasLimit > cap {
   101  		return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap)
   102  	}
   103  	// Verify that the gasUsed is <= gasLimit
   104  	if header.GasUsed > header.GasLimit {
   105  		return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
   106  	}
   107  	if config := chain.Config(); config.IsApricotPhase1(new(big.Int).SetUint64((header.Time))) {
   108  		if header.GasLimit != params.ApricotPhase1GasLimit {
   109  			return fmt.Errorf("expected gas limit to be %d, but found %d", params.ApricotPhase1GasLimit, header.GasLimit)
   110  		}
   111  	} else {
   112  		// Verify that the gas limit remains within allowed bounds
   113  		diff := int64(parent.GasLimit) - int64(header.GasLimit)
   114  		if diff < 0 {
   115  			diff *= -1
   116  		}
   117  		limit := parent.GasLimit / params.GasLimitBoundDivisor
   118  
   119  		if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit {
   120  			return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit)
   121  		}
   122  	}
   123  
   124  	// Verify that the block number is parent's +1
   125  	if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
   126  		return consensus.ErrInvalidNumber
   127  	}
   128  	// Verify the engine specific seal securing the block
   129  	return self.VerifySeal(chain, header)
   130  }
   131  
   132  func (self *DummyEngine) Author(header *types.Header) (common.Address, error) {
   133  	return header.Coinbase, nil
   134  }
   135  
   136  func (self *DummyEngine) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error {
   137  	// Short circuit if the header is known, or it's parent not
   138  	number := header.Number.Uint64()
   139  	if chain.GetHeader(header.Hash(), number) != nil {
   140  		return nil
   141  	}
   142  	parent := chain.GetHeader(header.ParentHash, number-1)
   143  	if parent == nil {
   144  		return consensus.ErrUnknownAncestor
   145  	}
   146  	// Sanity checks passed, do a proper verification
   147  	return self.verifyHeader(chain, header, parent, false)
   148  }
   149  
   150  func (self *DummyEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
   151  	if len(block.Uncles()) > 0 {
   152  		return errUnclesUnsupported
   153  	}
   154  	return nil
   155  }
   156  
   157  func (self *DummyEngine) VerifySeal(chain consensus.ChainHeaderReader, header *types.Header) error {
   158  	return nil
   159  }
   160  
   161  func (self *DummyEngine) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
   162  	header.Difficulty = big.NewInt(1)
   163  	return nil
   164  }
   165  
   166  func (self *DummyEngine) Finalize(
   167  	chain consensus.ChainHeaderReader, header *types.Header,
   168  	state *state.StateDB, txs []*types.Transaction, receipts []*types.Receipt,
   169  	uncles []*types.Header) error {
   170  	if self.cb.OnFinalize != nil {
   171  		return self.cb.OnFinalize(chain, header, state, txs, receipts, uncles)
   172  	}
   173  	return nil
   174  }
   175  
   176  func (self *DummyEngine) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
   177  	uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
   178  	var extdata []byte
   179  	if self.cb.OnFinalizeAndAssemble != nil {
   180  		ret, err := self.cb.OnFinalizeAndAssemble(header, state, txs)
   181  		extdata = ret
   182  		if err != nil {
   183  			return nil, err
   184  		}
   185  	}
   186  	// commit the final state root
   187  	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
   188  
   189  	// Header seems complete, assemble into a block and return
   190  	return types.NewBlock(
   191  		header, txs, uncles, receipts, new(trie.Trie), extdata,
   192  		chain.Config().IsApricotPhase1(new(big.Int).SetUint64(header.Time)),
   193  	), nil
   194  }
   195  
   196  func (self *DummyEngine) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int {
   197  	return big.NewInt(1)
   198  }
   199  
   200  func (self *DummyEngine) APIs(chain consensus.ChainHeaderReader) (res []rpc.API) {
   201  	res = nil
   202  	if self.cb.OnAPIs != nil {
   203  		res = self.cb.OnAPIs(chain)
   204  	}
   205  	return
   206  }
   207  
   208  func (self *DummyEngine) Close() error {
   209  	return nil
   210  }
   211  
   212  func (self *DummyEngine) ExtraStateChange(block *types.Block, statedb *state.StateDB) error {
   213  	if self.cb.OnExtraStateChange != nil {
   214  		return self.cb.OnExtraStateChange(block, statedb)
   215  	}
   216  	return nil
   217  }