github.com/ylsGit/go-ethereum@v1.6.5/light/lightchain.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package light 18 19 import ( 20 "context" 21 "math/big" 22 "sync" 23 "sync/atomic" 24 "time" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/consensus" 28 "github.com/ethereum/go-ethereum/core" 29 "github.com/ethereum/go-ethereum/core/types" 30 "github.com/ethereum/go-ethereum/ethdb" 31 "github.com/ethereum/go-ethereum/event" 32 "github.com/ethereum/go-ethereum/log" 33 "github.com/ethereum/go-ethereum/params" 34 "github.com/ethereum/go-ethereum/rlp" 35 "github.com/hashicorp/golang-lru" 36 ) 37 38 var ( 39 bodyCacheLimit = 256 40 blockCacheLimit = 256 41 ) 42 43 // LightChain represents a canonical chain that by default only handles block 44 // headers, downloading block bodies and receipts on demand through an ODR 45 // interface. It only does header validation during chain insertion. 46 type LightChain struct { 47 hc *core.HeaderChain 48 chainDb ethdb.Database 49 odr OdrBackend 50 eventMux *event.TypeMux 51 genesisBlock *types.Block 52 53 mu sync.RWMutex 54 chainmu sync.RWMutex 55 procmu sync.RWMutex 56 57 bodyCache *lru.Cache // Cache for the most recent block bodies 58 bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format 59 blockCache *lru.Cache // Cache for the most recent entire blocks 60 61 quit chan struct{} 62 running int32 // running must be called automically 63 // procInterrupt must be atomically called 64 procInterrupt int32 // interrupt signaler for block processing 65 wg sync.WaitGroup 66 67 engine consensus.Engine 68 } 69 70 // NewLightChain returns a fully initialised light chain using information 71 // available in the database. It initialises the default Ethereum header 72 // validator. 73 func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine, mux *event.TypeMux) (*LightChain, error) { 74 bodyCache, _ := lru.New(bodyCacheLimit) 75 bodyRLPCache, _ := lru.New(bodyCacheLimit) 76 blockCache, _ := lru.New(blockCacheLimit) 77 78 bc := &LightChain{ 79 chainDb: odr.Database(), 80 odr: odr, 81 eventMux: mux, 82 quit: make(chan struct{}), 83 bodyCache: bodyCache, 84 bodyRLPCache: bodyRLPCache, 85 blockCache: blockCache, 86 engine: engine, 87 } 88 var err error 89 bc.hc, err = core.NewHeaderChain(odr.Database(), config, bc.engine, bc.getProcInterrupt) 90 if err != nil { 91 return nil, err 92 } 93 bc.genesisBlock, _ = bc.GetBlockByNumber(NoOdr, 0) 94 if bc.genesisBlock == nil { 95 return nil, core.ErrNoGenesis 96 } 97 if bc.genesisBlock.Hash() == params.MainNetGenesisHash { 98 // add trusted CHT 99 WriteTrustedCht(bc.chainDb, TrustedCht{Number: 805, Root: common.HexToHash("85e4286fe0a730390245c49de8476977afdae0eb5530b277f62a52b12313d50f")}) 100 log.Info("Added trusted CHT for mainnet") 101 } 102 103 if err := bc.loadLastState(); err != nil { 104 return nil, err 105 } 106 // Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain 107 for hash := range core.BadHashes { 108 if header := bc.GetHeaderByHash(hash); header != nil { 109 log.Error("Found bad hash, rewinding chain", "number", header.Number, "hash", header.ParentHash) 110 bc.SetHead(header.Number.Uint64() - 1) 111 log.Error("Chain rewind was successful, resuming normal operation") 112 } 113 } 114 return bc, nil 115 } 116 117 func (self *LightChain) getProcInterrupt() bool { 118 return atomic.LoadInt32(&self.procInterrupt) == 1 119 } 120 121 // Odr returns the ODR backend of the chain 122 func (self *LightChain) Odr() OdrBackend { 123 return self.odr 124 } 125 126 // loadLastState loads the last known chain state from the database. This method 127 // assumes that the chain manager mutex is held. 128 func (self *LightChain) loadLastState() error { 129 if head := core.GetHeadHeaderHash(self.chainDb); head == (common.Hash{}) { 130 // Corrupt or empty database, init from scratch 131 self.Reset() 132 } else { 133 if header := self.GetHeaderByHash(head); header != nil { 134 self.hc.SetCurrentHeader(header) 135 } 136 } 137 138 // Issue a status log and return 139 header := self.hc.CurrentHeader() 140 headerTd := self.GetTd(header.Hash(), header.Number.Uint64()) 141 log.Info("Loaded most recent local header", "number", header.Number, "hash", header.Hash(), "td", headerTd) 142 143 return nil 144 } 145 146 // SetHead rewinds the local chain to a new head. Everything above the new 147 // head will be deleted and the new one set. 148 func (bc *LightChain) SetHead(head uint64) { 149 bc.mu.Lock() 150 defer bc.mu.Unlock() 151 152 bc.hc.SetHead(head, nil) 153 bc.loadLastState() 154 } 155 156 // GasLimit returns the gas limit of the current HEAD block. 157 func (self *LightChain) GasLimit() *big.Int { 158 self.mu.RLock() 159 defer self.mu.RUnlock() 160 161 return self.hc.CurrentHeader().GasLimit 162 } 163 164 // LastBlockHash return the hash of the HEAD block. 165 func (self *LightChain) LastBlockHash() common.Hash { 166 self.mu.RLock() 167 defer self.mu.RUnlock() 168 169 return self.hc.CurrentHeader().Hash() 170 } 171 172 // Status returns status information about the current chain such as the HEAD Td, 173 // the HEAD hash and the hash of the genesis block. 174 func (self *LightChain) Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) { 175 self.mu.RLock() 176 defer self.mu.RUnlock() 177 178 header := self.hc.CurrentHeader() 179 hash := header.Hash() 180 return self.GetTd(hash, header.Number.Uint64()), hash, self.genesisBlock.Hash() 181 } 182 183 // State returns a new mutable state based on the current HEAD block. 184 func (self *LightChain) State() *LightState { 185 return NewLightState(StateTrieID(self.hc.CurrentHeader()), self.odr) 186 } 187 188 // Reset purges the entire blockchain, restoring it to its genesis state. 189 func (bc *LightChain) Reset() { 190 bc.ResetWithGenesisBlock(bc.genesisBlock) 191 } 192 193 // ResetWithGenesisBlock purges the entire blockchain, restoring it to the 194 // specified genesis state. 195 func (bc *LightChain) ResetWithGenesisBlock(genesis *types.Block) { 196 // Dump the entire block chain and purge the caches 197 bc.SetHead(0) 198 199 bc.mu.Lock() 200 defer bc.mu.Unlock() 201 202 // Prepare the genesis block and reinitialise the chain 203 if err := core.WriteTd(bc.chainDb, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()); err != nil { 204 log.Crit("Failed to write genesis block TD", "err", err) 205 } 206 if err := core.WriteBlock(bc.chainDb, genesis); err != nil { 207 log.Crit("Failed to write genesis block", "err", err) 208 } 209 bc.genesisBlock = genesis 210 bc.hc.SetGenesis(bc.genesisBlock.Header()) 211 bc.hc.SetCurrentHeader(bc.genesisBlock.Header()) 212 } 213 214 // Accessors 215 216 // Engine retrieves the light chain's consensus engine. 217 func (bc *LightChain) Engine() consensus.Engine { return bc.engine } 218 219 // Genesis returns the genesis block 220 func (bc *LightChain) Genesis() *types.Block { 221 return bc.genesisBlock 222 } 223 224 // GetBody retrieves a block body (transactions and uncles) from the database 225 // or ODR service by hash, caching it if found. 226 func (self *LightChain) GetBody(ctx context.Context, hash common.Hash) (*types.Body, error) { 227 // Short circuit if the body's already in the cache, retrieve otherwise 228 if cached, ok := self.bodyCache.Get(hash); ok { 229 body := cached.(*types.Body) 230 return body, nil 231 } 232 body, err := GetBody(ctx, self.odr, hash, self.hc.GetBlockNumber(hash)) 233 if err != nil { 234 return nil, err 235 } 236 // Cache the found body for next time and return 237 self.bodyCache.Add(hash, body) 238 return body, nil 239 } 240 241 // GetBodyRLP retrieves a block body in RLP encoding from the database or 242 // ODR service by hash, caching it if found. 243 func (self *LightChain) GetBodyRLP(ctx context.Context, hash common.Hash) (rlp.RawValue, error) { 244 // Short circuit if the body's already in the cache, retrieve otherwise 245 if cached, ok := self.bodyRLPCache.Get(hash); ok { 246 return cached.(rlp.RawValue), nil 247 } 248 body, err := GetBodyRLP(ctx, self.odr, hash, self.hc.GetBlockNumber(hash)) 249 if err != nil { 250 return nil, err 251 } 252 // Cache the found body for next time and return 253 self.bodyRLPCache.Add(hash, body) 254 return body, nil 255 } 256 257 // HasBlock checks if a block is fully present in the database or not, caching 258 // it if present. 259 func (bc *LightChain) HasBlock(hash common.Hash) bool { 260 blk, _ := bc.GetBlockByHash(NoOdr, hash) 261 return blk != nil 262 } 263 264 // GetBlock retrieves a block from the database or ODR service by hash and number, 265 // caching it if found. 266 func (self *LightChain) GetBlock(ctx context.Context, hash common.Hash, number uint64) (*types.Block, error) { 267 // Short circuit if the block's already in the cache, retrieve otherwise 268 if block, ok := self.blockCache.Get(hash); ok { 269 return block.(*types.Block), nil 270 } 271 block, err := GetBlock(ctx, self.odr, hash, number) 272 if err != nil { 273 return nil, err 274 } 275 // Cache the found block for next time and return 276 self.blockCache.Add(block.Hash(), block) 277 return block, nil 278 } 279 280 // GetBlockByHash retrieves a block from the database or ODR service by hash, 281 // caching it if found. 282 func (self *LightChain) GetBlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { 283 return self.GetBlock(ctx, hash, self.hc.GetBlockNumber(hash)) 284 } 285 286 // GetBlockByNumber retrieves a block from the database or ODR service by 287 // number, caching it (associated with its hash) if found. 288 func (self *LightChain) GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error) { 289 hash, err := GetCanonicalHash(ctx, self.odr, number) 290 if hash == (common.Hash{}) || err != nil { 291 return nil, err 292 } 293 return self.GetBlock(ctx, hash, number) 294 } 295 296 // Stop stops the blockchain service. If any imports are currently in progress 297 // it will abort them using the procInterrupt. 298 func (bc *LightChain) Stop() { 299 if !atomic.CompareAndSwapInt32(&bc.running, 0, 1) { 300 return 301 } 302 close(bc.quit) 303 atomic.StoreInt32(&bc.procInterrupt, 1) 304 305 bc.wg.Wait() 306 log.Info("Blockchain manager stopped") 307 } 308 309 // Rollback is designed to remove a chain of links from the database that aren't 310 // certain enough to be valid. 311 func (self *LightChain) Rollback(chain []common.Hash) { 312 self.mu.Lock() 313 defer self.mu.Unlock() 314 315 for i := len(chain) - 1; i >= 0; i-- { 316 hash := chain[i] 317 318 if head := self.hc.CurrentHeader(); head.Hash() == hash { 319 self.hc.SetCurrentHeader(self.GetHeader(head.ParentHash, head.Number.Uint64()-1)) 320 } 321 } 322 } 323 324 // postChainEvents iterates over the events generated by a chain insertion and 325 // posts them into the event mux. 326 func (self *LightChain) postChainEvents(events []interface{}) { 327 for _, event := range events { 328 if event, ok := event.(core.ChainEvent); ok { 329 if self.LastBlockHash() == event.Hash { 330 self.eventMux.Post(core.ChainHeadEvent{Block: event.Block}) 331 } 332 } 333 // Fire the insertion events individually too 334 self.eventMux.Post(event) 335 } 336 } 337 338 // InsertHeaderChain attempts to insert the given header chain in to the local 339 // chain, possibly creating a reorg. If an error is returned, it will return the 340 // index number of the failing header as well an error describing what went wrong. 341 // 342 // The verify parameter can be used to fine tune whether nonce verification 343 // should be done or not. The reason behind the optional check is because some 344 // of the header retrieval mechanisms already need to verfy nonces, as well as 345 // because nonces can be verified sparsely, not needing to check each. 346 // 347 // In the case of a light chain, InsertHeaderChain also creates and posts light 348 // chain events when necessary. 349 func (self *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) { 350 start := time.Now() 351 if i, err := self.hc.ValidateHeaderChain(chain, checkFreq); err != nil { 352 return i, err 353 } 354 355 // Make sure only one thread manipulates the chain at once 356 self.chainmu.Lock() 357 defer func() { 358 self.chainmu.Unlock() 359 time.Sleep(time.Millisecond * 10) // ugly hack; do not hog chain lock in case syncing is CPU-limited by validation 360 }() 361 362 self.wg.Add(1) 363 defer self.wg.Done() 364 365 var events []interface{} 366 whFunc := func(header *types.Header) error { 367 self.mu.Lock() 368 defer self.mu.Unlock() 369 370 status, err := self.hc.WriteHeader(header) 371 372 switch status { 373 case core.CanonStatTy: 374 log.Debug("Inserted new header", "number", header.Number, "hash", header.Hash()) 375 events = append(events, core.ChainEvent{Block: types.NewBlockWithHeader(header), Hash: header.Hash()}) 376 377 case core.SideStatTy: 378 log.Debug("Inserted forked header", "number", header.Number, "hash", header.Hash()) 379 events = append(events, core.ChainSideEvent{Block: types.NewBlockWithHeader(header)}) 380 } 381 return err 382 } 383 i, err := self.hc.InsertHeaderChain(chain, whFunc, start) 384 go self.postChainEvents(events) 385 return i, err 386 } 387 388 // CurrentHeader retrieves the current head header of the canonical chain. The 389 // header is retrieved from the HeaderChain's internal cache. 390 func (self *LightChain) CurrentHeader() *types.Header { 391 self.mu.RLock() 392 defer self.mu.RUnlock() 393 394 return self.hc.CurrentHeader() 395 } 396 397 // GetTd retrieves a block's total difficulty in the canonical chain from the 398 // database by hash and number, caching it if found. 399 func (self *LightChain) GetTd(hash common.Hash, number uint64) *big.Int { 400 return self.hc.GetTd(hash, number) 401 } 402 403 // GetTdByHash retrieves a block's total difficulty in the canonical chain from the 404 // database by hash, caching it if found. 405 func (self *LightChain) GetTdByHash(hash common.Hash) *big.Int { 406 return self.hc.GetTdByHash(hash) 407 } 408 409 // GetHeader retrieves a block header from the database by hash and number, 410 // caching it if found. 411 func (self *LightChain) GetHeader(hash common.Hash, number uint64) *types.Header { 412 return self.hc.GetHeader(hash, number) 413 } 414 415 // GetHeaderByHash retrieves a block header from the database by hash, caching it if 416 // found. 417 func (self *LightChain) GetHeaderByHash(hash common.Hash) *types.Header { 418 return self.hc.GetHeaderByHash(hash) 419 } 420 421 // HasHeader checks if a block header is present in the database or not, caching 422 // it if present. 423 func (bc *LightChain) HasHeader(hash common.Hash) bool { 424 return bc.hc.HasHeader(hash) 425 } 426 427 // GetBlockHashesFromHash retrieves a number of block hashes starting at a given 428 // hash, fetching towards the genesis block. 429 func (self *LightChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash { 430 return self.hc.GetBlockHashesFromHash(hash, max) 431 } 432 433 // GetHeaderByNumber retrieves a block header from the database by number, 434 // caching it (associated with its hash) if found. 435 func (self *LightChain) GetHeaderByNumber(number uint64) *types.Header { 436 return self.hc.GetHeaderByNumber(number) 437 } 438 439 // GetHeaderByNumberOdr retrieves a block header from the database or network 440 // by number, caching it (associated with its hash) if found. 441 func (self *LightChain) GetHeaderByNumberOdr(ctx context.Context, number uint64) (*types.Header, error) { 442 if header := self.hc.GetHeaderByNumber(number); header != nil { 443 return header, nil 444 } 445 return GetHeaderByNumber(ctx, self.odr, number) 446 } 447 448 func (self *LightChain) SyncCht(ctx context.Context) bool { 449 headNum := self.CurrentHeader().Number.Uint64() 450 cht := GetTrustedCht(self.chainDb) 451 if headNum+1 < cht.Number*ChtFrequency { 452 num := cht.Number*ChtFrequency - 1 453 header, err := GetHeaderByNumber(ctx, self.odr, num) 454 if header != nil && err == nil { 455 self.mu.Lock() 456 if self.hc.CurrentHeader().Number.Uint64() < header.Number.Uint64() { 457 self.hc.SetCurrentHeader(header) 458 } 459 self.mu.Unlock() 460 return true 461 } 462 } 463 return false 464 } 465 466 // LockChain locks the chain mutex for reading so that multiple canonical hashes can be 467 // retrieved while it is guaranteed that they belong to the same version of the chain 468 func (self *LightChain) LockChain() { 469 self.chainmu.RLock() 470 } 471 472 // UnlockChain unlocks the chain mutex 473 func (self *LightChain) UnlockChain() { 474 self.chainmu.RUnlock() 475 }