github.com/eliasnaur/go-ethereum@v1.6.8-0.20170717120422-6e13bd050756/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 // Reset purges the entire blockchain, restoring it to its genesis state. 184 func (bc *LightChain) Reset() { 185 bc.ResetWithGenesisBlock(bc.genesisBlock) 186 } 187 188 // ResetWithGenesisBlock purges the entire blockchain, restoring it to the 189 // specified genesis state. 190 func (bc *LightChain) ResetWithGenesisBlock(genesis *types.Block) { 191 // Dump the entire block chain and purge the caches 192 bc.SetHead(0) 193 194 bc.mu.Lock() 195 defer bc.mu.Unlock() 196 197 // Prepare the genesis block and reinitialise the chain 198 if err := core.WriteTd(bc.chainDb, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()); err != nil { 199 log.Crit("Failed to write genesis block TD", "err", err) 200 } 201 if err := core.WriteBlock(bc.chainDb, genesis); err != nil { 202 log.Crit("Failed to write genesis block", "err", err) 203 } 204 bc.genesisBlock = genesis 205 bc.hc.SetGenesis(bc.genesisBlock.Header()) 206 bc.hc.SetCurrentHeader(bc.genesisBlock.Header()) 207 } 208 209 // Accessors 210 211 // Engine retrieves the light chain's consensus engine. 212 func (bc *LightChain) Engine() consensus.Engine { return bc.engine } 213 214 // Genesis returns the genesis block 215 func (bc *LightChain) Genesis() *types.Block { 216 return bc.genesisBlock 217 } 218 219 // GetBody retrieves a block body (transactions and uncles) from the database 220 // or ODR service by hash, caching it if found. 221 func (self *LightChain) GetBody(ctx context.Context, hash common.Hash) (*types.Body, error) { 222 // Short circuit if the body's already in the cache, retrieve otherwise 223 if cached, ok := self.bodyCache.Get(hash); ok { 224 body := cached.(*types.Body) 225 return body, nil 226 } 227 body, err := GetBody(ctx, self.odr, hash, self.hc.GetBlockNumber(hash)) 228 if err != nil { 229 return nil, err 230 } 231 // Cache the found body for next time and return 232 self.bodyCache.Add(hash, body) 233 return body, nil 234 } 235 236 // GetBodyRLP retrieves a block body in RLP encoding from the database or 237 // ODR service by hash, caching it if found. 238 func (self *LightChain) GetBodyRLP(ctx context.Context, hash common.Hash) (rlp.RawValue, error) { 239 // Short circuit if the body's already in the cache, retrieve otherwise 240 if cached, ok := self.bodyRLPCache.Get(hash); ok { 241 return cached.(rlp.RawValue), nil 242 } 243 body, err := GetBodyRLP(ctx, self.odr, hash, self.hc.GetBlockNumber(hash)) 244 if err != nil { 245 return nil, err 246 } 247 // Cache the found body for next time and return 248 self.bodyRLPCache.Add(hash, body) 249 return body, nil 250 } 251 252 // HasBlock checks if a block is fully present in the database or not, caching 253 // it if present. 254 func (bc *LightChain) HasBlock(hash common.Hash) bool { 255 blk, _ := bc.GetBlockByHash(NoOdr, hash) 256 return blk != nil 257 } 258 259 // GetBlock retrieves a block from the database or ODR service by hash and number, 260 // caching it if found. 261 func (self *LightChain) GetBlock(ctx context.Context, hash common.Hash, number uint64) (*types.Block, error) { 262 // Short circuit if the block's already in the cache, retrieve otherwise 263 if block, ok := self.blockCache.Get(hash); ok { 264 return block.(*types.Block), nil 265 } 266 block, err := GetBlock(ctx, self.odr, hash, number) 267 if err != nil { 268 return nil, err 269 } 270 // Cache the found block for next time and return 271 self.blockCache.Add(block.Hash(), block) 272 return block, nil 273 } 274 275 // GetBlockByHash retrieves a block from the database or ODR service by hash, 276 // caching it if found. 277 func (self *LightChain) GetBlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { 278 return self.GetBlock(ctx, hash, self.hc.GetBlockNumber(hash)) 279 } 280 281 // GetBlockByNumber retrieves a block from the database or ODR service by 282 // number, caching it (associated with its hash) if found. 283 func (self *LightChain) GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error) { 284 hash, err := GetCanonicalHash(ctx, self.odr, number) 285 if hash == (common.Hash{}) || err != nil { 286 return nil, err 287 } 288 return self.GetBlock(ctx, hash, number) 289 } 290 291 // Stop stops the blockchain service. If any imports are currently in progress 292 // it will abort them using the procInterrupt. 293 func (bc *LightChain) Stop() { 294 if !atomic.CompareAndSwapInt32(&bc.running, 0, 1) { 295 return 296 } 297 close(bc.quit) 298 atomic.StoreInt32(&bc.procInterrupt, 1) 299 300 bc.wg.Wait() 301 log.Info("Blockchain manager stopped") 302 } 303 304 // Rollback is designed to remove a chain of links from the database that aren't 305 // certain enough to be valid. 306 func (self *LightChain) Rollback(chain []common.Hash) { 307 self.mu.Lock() 308 defer self.mu.Unlock() 309 310 for i := len(chain) - 1; i >= 0; i-- { 311 hash := chain[i] 312 313 if head := self.hc.CurrentHeader(); head.Hash() == hash { 314 self.hc.SetCurrentHeader(self.GetHeader(head.ParentHash, head.Number.Uint64()-1)) 315 } 316 } 317 } 318 319 // postChainEvents iterates over the events generated by a chain insertion and 320 // posts them into the event mux. 321 func (self *LightChain) postChainEvents(events []interface{}) { 322 for _, event := range events { 323 if event, ok := event.(core.ChainEvent); ok { 324 if self.LastBlockHash() == event.Hash { 325 self.eventMux.Post(core.ChainHeadEvent{Block: event.Block}) 326 } 327 } 328 // Fire the insertion events individually too 329 self.eventMux.Post(event) 330 } 331 } 332 333 // InsertHeaderChain attempts to insert the given header chain in to the local 334 // chain, possibly creating a reorg. If an error is returned, it will return the 335 // index number of the failing header as well an error describing what went wrong. 336 // 337 // The verify parameter can be used to fine tune whether nonce verification 338 // should be done or not. The reason behind the optional check is because some 339 // of the header retrieval mechanisms already need to verfy nonces, as well as 340 // because nonces can be verified sparsely, not needing to check each. 341 // 342 // In the case of a light chain, InsertHeaderChain also creates and posts light 343 // chain events when necessary. 344 func (self *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) { 345 start := time.Now() 346 if i, err := self.hc.ValidateHeaderChain(chain, checkFreq); err != nil { 347 return i, err 348 } 349 350 // Make sure only one thread manipulates the chain at once 351 self.chainmu.Lock() 352 defer func() { 353 self.chainmu.Unlock() 354 time.Sleep(time.Millisecond * 10) // ugly hack; do not hog chain lock in case syncing is CPU-limited by validation 355 }() 356 357 self.wg.Add(1) 358 defer self.wg.Done() 359 360 var events []interface{} 361 whFunc := func(header *types.Header) error { 362 self.mu.Lock() 363 defer self.mu.Unlock() 364 365 status, err := self.hc.WriteHeader(header) 366 367 switch status { 368 case core.CanonStatTy: 369 log.Debug("Inserted new header", "number", header.Number, "hash", header.Hash()) 370 events = append(events, core.ChainEvent{Block: types.NewBlockWithHeader(header), Hash: header.Hash()}) 371 372 case core.SideStatTy: 373 log.Debug("Inserted forked header", "number", header.Number, "hash", header.Hash()) 374 events = append(events, core.ChainSideEvent{Block: types.NewBlockWithHeader(header)}) 375 } 376 return err 377 } 378 i, err := self.hc.InsertHeaderChain(chain, whFunc, start) 379 go self.postChainEvents(events) 380 return i, err 381 } 382 383 // CurrentHeader retrieves the current head header of the canonical chain. The 384 // header is retrieved from the HeaderChain's internal cache. 385 func (self *LightChain) CurrentHeader() *types.Header { 386 self.mu.RLock() 387 defer self.mu.RUnlock() 388 389 return self.hc.CurrentHeader() 390 } 391 392 // GetTd retrieves a block's total difficulty in the canonical chain from the 393 // database by hash and number, caching it if found. 394 func (self *LightChain) GetTd(hash common.Hash, number uint64) *big.Int { 395 return self.hc.GetTd(hash, number) 396 } 397 398 // GetTdByHash retrieves a block's total difficulty in the canonical chain from the 399 // database by hash, caching it if found. 400 func (self *LightChain) GetTdByHash(hash common.Hash) *big.Int { 401 return self.hc.GetTdByHash(hash) 402 } 403 404 // GetHeader retrieves a block header from the database by hash and number, 405 // caching it if found. 406 func (self *LightChain) GetHeader(hash common.Hash, number uint64) *types.Header { 407 return self.hc.GetHeader(hash, number) 408 } 409 410 // GetHeaderByHash retrieves a block header from the database by hash, caching it if 411 // found. 412 func (self *LightChain) GetHeaderByHash(hash common.Hash) *types.Header { 413 return self.hc.GetHeaderByHash(hash) 414 } 415 416 // HasHeader checks if a block header is present in the database or not, caching 417 // it if present. 418 func (bc *LightChain) HasHeader(hash common.Hash) bool { 419 return bc.hc.HasHeader(hash) 420 } 421 422 // GetBlockHashesFromHash retrieves a number of block hashes starting at a given 423 // hash, fetching towards the genesis block. 424 func (self *LightChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash { 425 return self.hc.GetBlockHashesFromHash(hash, max) 426 } 427 428 // GetHeaderByNumber retrieves a block header from the database by number, 429 // caching it (associated with its hash) if found. 430 func (self *LightChain) GetHeaderByNumber(number uint64) *types.Header { 431 return self.hc.GetHeaderByNumber(number) 432 } 433 434 // GetHeaderByNumberOdr retrieves a block header from the database or network 435 // by number, caching it (associated with its hash) if found. 436 func (self *LightChain) GetHeaderByNumberOdr(ctx context.Context, number uint64) (*types.Header, error) { 437 if header := self.hc.GetHeaderByNumber(number); header != nil { 438 return header, nil 439 } 440 return GetHeaderByNumber(ctx, self.odr, number) 441 } 442 443 func (self *LightChain) SyncCht(ctx context.Context) bool { 444 headNum := self.CurrentHeader().Number.Uint64() 445 cht := GetTrustedCht(self.chainDb) 446 if headNum+1 < cht.Number*ChtFrequency { 447 num := cht.Number*ChtFrequency - 1 448 header, err := GetHeaderByNumber(ctx, self.odr, num) 449 if header != nil && err == nil { 450 self.mu.Lock() 451 if self.hc.CurrentHeader().Number.Uint64() < header.Number.Uint64() { 452 self.hc.SetCurrentHeader(header) 453 } 454 self.mu.Unlock() 455 return true 456 } 457 } 458 return false 459 } 460 461 // LockChain locks the chain mutex for reading so that multiple canonical hashes can be 462 // retrieved while it is guaranteed that they belong to the same version of the chain 463 func (self *LightChain) LockChain() { 464 self.chainmu.RLock() 465 } 466 467 // UnlockChain unlocks the chain mutex 468 func (self *LightChain) UnlockChain() { 469 self.chainmu.RUnlock() 470 }