gitlab.com/flarenetwork/coreth@v0.1.1/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/ethereum/go-ethereum/common"
    37  	"github.com/ethereum/go-ethereum/ethdb"
    38  	lru "github.com/hashicorp/golang-lru"
    39  	"gitlab.com/flarenetwork/coreth/consensus"
    40  	"gitlab.com/flarenetwork/coreth/core/rawdb"
    41  	"gitlab.com/flarenetwork/coreth/core/types"
    42  	"gitlab.com/flarenetwork/coreth/params"
    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: (1) total difficult
    59  // (2) header (3) block hash -> number mapping (4) canonical number -> hash mapping
    60  // and (5) 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  // GetTd retrieves a block's total difficulty in the canonical chain from the
   135  // database by hash and number, caching it if found.
   136  func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int {
   137  	// Short circuit if the td's already in the cache, retrieve otherwise
   138  	if cached, ok := hc.tdCache.Get(hash); ok {
   139  		return cached.(*big.Int)
   140  	}
   141  	td := rawdb.ReadTd(hc.chainDb, hash, number)
   142  	if td == nil {
   143  		return nil
   144  	}
   145  	// Cache the found body for next time and return
   146  	hc.tdCache.Add(hash, td)
   147  	return td
   148  }
   149  
   150  // GetTdByHash retrieves a block's total difficulty in the canonical chain from the
   151  // database by hash, caching it if found.
   152  func (hc *HeaderChain) GetTdByHash(hash common.Hash) *big.Int {
   153  	number := hc.GetBlockNumber(hash)
   154  	if number == nil {
   155  		return nil
   156  	}
   157  	return hc.GetTd(hash, *number)
   158  }
   159  
   160  // GetHeader retrieves a block header from the database by hash and number,
   161  // caching it if found.
   162  func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header {
   163  	// Short circuit if the header's already in the cache, retrieve otherwise
   164  	if header, ok := hc.headerCache.Get(hash); ok {
   165  		return header.(*types.Header)
   166  	}
   167  	header := rawdb.ReadHeader(hc.chainDb, hash, number)
   168  	if header == nil {
   169  		return nil
   170  	}
   171  	// Cache the found header for next time and return
   172  	hc.headerCache.Add(hash, header)
   173  	return header
   174  }
   175  
   176  // GetHeaderByHash retrieves a block header from the database by hash, caching it if
   177  // found.
   178  func (hc *HeaderChain) GetHeaderByHash(hash common.Hash) *types.Header {
   179  	number := hc.GetBlockNumber(hash)
   180  	if number == nil {
   181  		return nil
   182  	}
   183  	return hc.GetHeader(hash, *number)
   184  }
   185  
   186  // HasHeader checks if a block header is present in the database or not.
   187  // In theory, if header is present in the database, all relative components
   188  // like td and hash->number should be present too.
   189  func (hc *HeaderChain) HasHeader(hash common.Hash, number uint64) bool {
   190  	if hc.numberCache.Contains(hash) || hc.headerCache.Contains(hash) {
   191  		return true
   192  	}
   193  	return rawdb.HasHeader(hc.chainDb, hash, number)
   194  }
   195  
   196  // GetHeaderByNumber retrieves a block header from the database by number,
   197  // caching it (associated with its hash) if found.
   198  func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header {
   199  	hash := rawdb.ReadCanonicalHash(hc.chainDb, number)
   200  	if hash == (common.Hash{}) {
   201  		return nil
   202  	}
   203  	return hc.GetHeader(hash, number)
   204  }
   205  
   206  func (hc *HeaderChain) GetCanonicalHash(number uint64) common.Hash {
   207  	return rawdb.ReadCanonicalHash(hc.chainDb, number)
   208  }
   209  
   210  // CurrentHeader retrieves the current head header of the canonical chain. The
   211  // header is retrieved from the HeaderChain's internal cache.
   212  func (hc *HeaderChain) CurrentHeader() *types.Header {
   213  	return hc.currentHeader.Load().(*types.Header)
   214  }
   215  
   216  // SetCurrentHeader sets the in-memory head header marker of the canonical chan
   217  // as the given header.
   218  func (hc *HeaderChain) SetCurrentHeader(head *types.Header) {
   219  	hc.currentHeader.Store(head)
   220  	hc.currentHeaderHash = head.Hash()
   221  }
   222  
   223  // SetGenesis sets a new genesis block header for the chain
   224  func (hc *HeaderChain) SetGenesis(head *types.Header) {
   225  	hc.genesisHeader = head
   226  }
   227  
   228  // Config retrieves the header chain's chain configuration.
   229  func (hc *HeaderChain) Config() *params.ChainConfig { return hc.config }
   230  
   231  // Engine retrieves the header chain's consensus engine.
   232  func (hc *HeaderChain) Engine() consensus.Engine { return hc.engine }
   233  
   234  // GetBlock implements consensus.ChainReader, and returns nil for every input as
   235  // a header chain does not have blocks available for retrieval.
   236  func (hc *HeaderChain) GetBlock(hash common.Hash, number uint64) *types.Block {
   237  	return nil
   238  }