github.com/MetalBlockchain/subnet-evm@v0.4.9/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/MetalBlockchain/subnet-evm/consensus" 37 "github.com/MetalBlockchain/subnet-evm/core/rawdb" 38 "github.com/MetalBlockchain/subnet-evm/core/types" 39 "github.com/MetalBlockchain/subnet-evm/ethdb" 40 "github.com/MetalBlockchain/subnet-evm/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 acceptedNumberCache FIFOCache[uint64, *types.Header] // Cache for most recent accepted heights to headers (only modified in accept) 77 78 rand *mrand.Rand 79 engine consensus.Engine 80 } 81 82 // NewHeaderChain creates a new HeaderChain structure. ProcInterrupt points 83 // to the parent's interrupt semaphore. 84 func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, cacheConfig *CacheConfig, engine consensus.Engine) (*HeaderChain, error) { 85 headerCache, _ := lru.New(headerCacheLimit) 86 tdCache, _ := lru.New(tdCacheLimit) 87 numberCache, _ := lru.New(numberCacheLimit) 88 acceptedNumberCache := NewFIFOCache[uint64, *types.Header](cacheConfig.AcceptedCacheSize) 89 90 // Seed a fast but crypto originating random generator 91 seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) 92 if err != nil { 93 return nil, err 94 } 95 96 hc := &HeaderChain{ 97 config: config, 98 chainDb: chainDb, 99 headerCache: headerCache, 100 tdCache: tdCache, 101 numberCache: numberCache, 102 acceptedNumberCache: acceptedNumberCache, 103 rand: mrand.New(mrand.NewSource(seed.Int64())), 104 engine: engine, 105 } 106 107 hc.genesisHeader = hc.GetHeaderByNumber(0) 108 if hc.genesisHeader == nil { 109 return nil, ErrNoGenesis 110 } 111 112 hc.currentHeader.Store(hc.genesisHeader) 113 if head := rawdb.ReadHeadBlockHash(chainDb); head != (common.Hash{}) { 114 if chead := hc.GetHeaderByHash(head); chead != nil { 115 hc.currentHeader.Store(chead) 116 } 117 } 118 hc.currentHeaderHash = hc.CurrentHeader().Hash() 119 120 return hc, nil 121 } 122 123 // GetBlockNumber retrieves the block number belonging to the given hash 124 // from the cache or database 125 func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 { 126 if cached, ok := hc.numberCache.Get(hash); ok { 127 number := cached.(uint64) 128 return &number 129 } 130 number := rawdb.ReadHeaderNumber(hc.chainDb, hash) 131 if number != nil { 132 hc.numberCache.Add(hash, *number) 133 } 134 return number 135 } 136 137 // GetHeader retrieves a block header from the database by hash and number, 138 // caching it if found. 139 func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header { 140 // Short circuit if the header's already in the cache, retrieve otherwise 141 if header, ok := hc.headerCache.Get(hash); ok { 142 return header.(*types.Header) 143 } 144 header := rawdb.ReadHeader(hc.chainDb, hash, number) 145 if header == nil { 146 return nil 147 } 148 // Cache the found header for next time and return 149 hc.headerCache.Add(hash, header) 150 return header 151 } 152 153 // GetHeaderByHash retrieves a block header from the database by hash, caching it if 154 // found. 155 func (hc *HeaderChain) GetHeaderByHash(hash common.Hash) *types.Header { 156 number := hc.GetBlockNumber(hash) 157 if number == nil { 158 return nil 159 } 160 return hc.GetHeader(hash, *number) 161 } 162 163 // HasHeader checks if a block header is present in the database or not. 164 // In theory, if header is present in the database, all relative components 165 // like td and hash->number should be present too. 166 func (hc *HeaderChain) HasHeader(hash common.Hash, number uint64) bool { 167 if hc.numberCache.Contains(hash) || hc.headerCache.Contains(hash) { 168 return true 169 } 170 return rawdb.HasHeader(hc.chainDb, hash, number) 171 } 172 173 // GetHeaderByNumber retrieves a block header from the database by number, 174 // caching it (associated with its hash) if found. 175 func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header { 176 if cachedHeader, ok := hc.acceptedNumberCache.Get(number); ok { 177 return cachedHeader 178 } 179 hash := rawdb.ReadCanonicalHash(hc.chainDb, number) 180 if hash == (common.Hash{}) { 181 return nil 182 } 183 return hc.GetHeader(hash, number) 184 } 185 186 func (hc *HeaderChain) GetCanonicalHash(number uint64) common.Hash { 187 return rawdb.ReadCanonicalHash(hc.chainDb, number) 188 } 189 190 // CurrentHeader retrieves the current head header of the canonical chain. The 191 // header is retrieved from the HeaderChain's internal cache. 192 func (hc *HeaderChain) CurrentHeader() *types.Header { 193 return hc.currentHeader.Load().(*types.Header) 194 } 195 196 // SetCurrentHeader sets the in-memory head header marker of the canonical chan 197 // as the given header. 198 func (hc *HeaderChain) SetCurrentHeader(head *types.Header) { 199 hc.currentHeader.Store(head) 200 hc.currentHeaderHash = head.Hash() 201 } 202 203 // SetGenesis sets a new genesis block header for the chain 204 func (hc *HeaderChain) SetGenesis(head *types.Header) { 205 hc.genesisHeader = head 206 } 207 208 // Config retrieves the header chain's chain configuration. 209 func (hc *HeaderChain) Config() *params.ChainConfig { return hc.config } 210 211 // Engine retrieves the header chain's consensus engine. 212 func (hc *HeaderChain) Engine() consensus.Engine { return hc.engine } 213 214 // GetBlock implements consensus.ChainReader, and returns nil for every input as 215 // a header chain does not have blocks available for retrieval. 216 func (hc *HeaderChain) GetBlock(hash common.Hash, number uint64) *types.Block { 217 return nil 218 }