github.com/dim4egster/coreth@v0.10.2/core/headerchain.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2015 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package core
    28  
    29  import (
    30  	crand "crypto/rand"
    31  	"math"
    32  	"math/big"
    33  	mrand "math/rand"
    34  	"sync/atomic"
    35  
    36  	"github.com/dim4egster/coreth/consensus"
    37  	"github.com/dim4egster/coreth/core/rawdb"
    38  	"github.com/dim4egster/coreth/core/types"
    39  	"github.com/dim4egster/coreth/ethdb"
    40  	"github.com/dim4egster/coreth/params"
    41  	"github.com/ethereum/go-ethereum/common"
    42  	lru "github.com/hashicorp/golang-lru"
    43  )
    44  
    45  const (
    46  	headerCacheLimit = 512
    47  	tdCacheLimit     = 1024
    48  	numberCacheLimit = 2048
    49  )
    50  
    51  // HeaderChain implements the basic block header chain logic that is shared by
    52  // core.BlockChain and light.LightChain. It is not usable in itself, only as
    53  // a part of either structure.
    54  //
    55  // HeaderChain is responsible for maintaining the header chain including the
    56  // header query and updating.
    57  //
    58  // The components maintained by headerchain includes:
    59  // (1) header (2) block hash -> number mapping (3) canonical number -> hash mapping
    60  // and (4) head header flag.
    61  //
    62  // It is not thread safe either, the encapsulating chain structures should do
    63  // the necessary mutex locking/unlocking.
    64  type HeaderChain struct {
    65  	config *params.ChainConfig
    66  
    67  	chainDb       ethdb.Database
    68  	genesisHeader *types.Header
    69  
    70  	currentHeader     atomic.Value // Current head of the header chain (may be above the block chain!)
    71  	currentHeaderHash common.Hash  // Hash of the current head of the header chain (prevent recomputing all the time)
    72  
    73  	headerCache *lru.Cache // Cache for the most recent block headers
    74  	tdCache     *lru.Cache // Cache for the most recent block total difficulties
    75  	numberCache *lru.Cache // Cache for the most recent block numbers
    76  
    77  	rand   *mrand.Rand
    78  	engine consensus.Engine
    79  }
    80  
    81  // NewHeaderChain creates a new HeaderChain structure. ProcInterrupt points
    82  // to the parent's interrupt semaphore.
    83  func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine consensus.Engine) (*HeaderChain, error) {
    84  	headerCache, _ := lru.New(headerCacheLimit)
    85  	tdCache, _ := lru.New(tdCacheLimit)
    86  	numberCache, _ := lru.New(numberCacheLimit)
    87  
    88  	// Seed a fast but crypto originating random generator
    89  	seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	hc := &HeaderChain{
    95  		config:      config,
    96  		chainDb:     chainDb,
    97  		headerCache: headerCache,
    98  		tdCache:     tdCache,
    99  		numberCache: numberCache,
   100  		rand:        mrand.New(mrand.NewSource(seed.Int64())),
   101  		engine:      engine,
   102  	}
   103  
   104  	hc.genesisHeader = hc.GetHeaderByNumber(0)
   105  	if hc.genesisHeader == nil {
   106  		return nil, ErrNoGenesis
   107  	}
   108  
   109  	hc.currentHeader.Store(hc.genesisHeader)
   110  	if head := rawdb.ReadHeadBlockHash(chainDb); head != (common.Hash{}) {
   111  		if chead := hc.GetHeaderByHash(head); chead != nil {
   112  			hc.currentHeader.Store(chead)
   113  		}
   114  	}
   115  	hc.currentHeaderHash = hc.CurrentHeader().Hash()
   116  
   117  	return hc, nil
   118  }
   119  
   120  // GetBlockNumber retrieves the block number belonging to the given hash
   121  // from the cache or database
   122  func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 {
   123  	if cached, ok := hc.numberCache.Get(hash); ok {
   124  		number := cached.(uint64)
   125  		return &number
   126  	}
   127  	number := rawdb.ReadHeaderNumber(hc.chainDb, hash)
   128  	if number != nil {
   129  		hc.numberCache.Add(hash, *number)
   130  	}
   131  	return number
   132  }
   133  
   134  // GetHeader retrieves a block header from the database by hash and number,
   135  // caching it if found.
   136  func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header {
   137  	// Short circuit if the header's already in the cache, retrieve otherwise
   138  	if header, ok := hc.headerCache.Get(hash); ok {
   139  		return header.(*types.Header)
   140  	}
   141  	header := rawdb.ReadHeader(hc.chainDb, hash, number)
   142  	if header == nil {
   143  		return nil
   144  	}
   145  	// Cache the found header for next time and return
   146  	hc.headerCache.Add(hash, header)
   147  	return header
   148  }
   149  
   150  // GetHeaderByHash retrieves a block header from the database by hash, caching it if
   151  // found.
   152  func (hc *HeaderChain) GetHeaderByHash(hash common.Hash) *types.Header {
   153  	number := hc.GetBlockNumber(hash)
   154  	if number == nil {
   155  		return nil
   156  	}
   157  	return hc.GetHeader(hash, *number)
   158  }
   159  
   160  // HasHeader checks if a block header is present in the database or not.
   161  // In theory, if header is present in the database, all relative components
   162  // like td and hash->number should be present too.
   163  func (hc *HeaderChain) HasHeader(hash common.Hash, number uint64) bool {
   164  	if hc.numberCache.Contains(hash) || hc.headerCache.Contains(hash) {
   165  		return true
   166  	}
   167  	return rawdb.HasHeader(hc.chainDb, hash, number)
   168  }
   169  
   170  // GetHeaderByNumber retrieves a block header from the database by number,
   171  // caching it (associated with its hash) if found.
   172  func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header {
   173  	hash := rawdb.ReadCanonicalHash(hc.chainDb, number)
   174  	if hash == (common.Hash{}) {
   175  		return nil
   176  	}
   177  	return hc.GetHeader(hash, number)
   178  }
   179  
   180  func (hc *HeaderChain) GetCanonicalHash(number uint64) common.Hash {
   181  	return rawdb.ReadCanonicalHash(hc.chainDb, number)
   182  }
   183  
   184  // CurrentHeader retrieves the current head header of the canonical chain. The
   185  // header is retrieved from the HeaderChain's internal cache.
   186  func (hc *HeaderChain) CurrentHeader() *types.Header {
   187  	return hc.currentHeader.Load().(*types.Header)
   188  }
   189  
   190  // SetCurrentHeader sets the in-memory head header marker of the canonical chan
   191  // as the given header.
   192  func (hc *HeaderChain) SetCurrentHeader(head *types.Header) {
   193  	hc.currentHeader.Store(head)
   194  	hc.currentHeaderHash = head.Hash()
   195  }
   196  
   197  // SetGenesis sets a new genesis block header for the chain
   198  func (hc *HeaderChain) SetGenesis(head *types.Header) {
   199  	hc.genesisHeader = head
   200  }
   201  
   202  // Config retrieves the header chain's chain configuration.
   203  func (hc *HeaderChain) Config() *params.ChainConfig { return hc.config }
   204  
   205  // Engine retrieves the header chain's consensus engine.
   206  func (hc *HeaderChain) Engine() consensus.Engine { return hc.engine }
   207  
   208  // GetBlock implements consensus.ChainReader, and returns nil for every input as
   209  // a header chain does not have blocks available for retrieval.
   210  func (hc *HeaderChain) GetBlock(hash common.Hash, number uint64) *types.Block {
   211  	return nil
   212  }