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 }