github.com/klaytn/klaytn@v1.12.1/blockchain/headerchain.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from core/headerchain.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package blockchain 22 23 import ( 24 crand "crypto/rand" 25 "errors" 26 "fmt" 27 "math" 28 "math/big" 29 mrand "math/rand" 30 "sync/atomic" 31 "time" 32 33 "github.com/klaytn/klaytn/blockchain/state" 34 "github.com/klaytn/klaytn/blockchain/types" 35 "github.com/klaytn/klaytn/common" 36 "github.com/klaytn/klaytn/consensus" 37 "github.com/klaytn/klaytn/params" 38 "github.com/klaytn/klaytn/storage/database" 39 ) 40 41 // HeaderChain implements the basic block header chain logic that is shared by 42 // blockchain.BlockChain and light.LightChain. It is not usable in itself, only as 43 // a part of either structure. 44 // It is not thread safe either, the encapsulating chain structures should do 45 // the necessary mutex locking/unlocking. 46 type HeaderChain struct { 47 config *params.ChainConfig 48 49 chainDB database.DBManager 50 genesisHeader *types.Header 51 52 currentHeader atomic.Value 53 currentHeaderHash common.Hash 54 55 procInterrupt func() bool 56 57 rand *mrand.Rand 58 engine consensus.Engine 59 } 60 61 // NewHeaderChain creates a new HeaderChain structure. 62 // 63 // getValidator should return the parent's validator 64 // procInterrupt points to the parent's interrupt semaphore 65 // wg points to the parent's shutdown wait group 66 func NewHeaderChain(chainDB database.DBManager, config *params.ChainConfig, engine consensus.Engine, procInterrupt func() bool) (*HeaderChain, error) { 67 // Seed a fast but crypto originating random generator 68 seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) 69 if err != nil { 70 return nil, err 71 } 72 73 hc := &HeaderChain{ 74 config: config, 75 chainDB: chainDB, 76 procInterrupt: procInterrupt, 77 rand: mrand.New(mrand.NewSource(seed.Int64())), 78 engine: engine, 79 } 80 81 hc.genesisHeader = hc.GetHeaderByNumber(0) 82 if hc.genesisHeader == nil { 83 return nil, ErrNoGenesis 84 } 85 86 hc.currentHeader.Store(hc.genesisHeader) 87 if head := chainDB.ReadHeadBlockHash(); head != (common.Hash{}) { 88 if chead := hc.GetHeaderByHash(head); chead != nil { 89 hc.currentHeader.Store(chead) 90 } else if head := chainDB.ReadHeadBlockBackupHash(); head != (common.Hash{}) { 91 if chead := hc.GetHeaderByHash(head); chead != nil { 92 hc.currentHeader.Store(chead) 93 } 94 } 95 } 96 hc.currentHeaderHash = hc.CurrentHeader().Hash() 97 98 return hc, nil 99 } 100 101 // GetBlockNumber retrieves the block number belonging to the given hash 102 // from the cache or database 103 func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 { 104 return hc.chainDB.ReadHeaderNumber(hash) 105 } 106 107 // WriteHeader writes a header into the local chain, given that its parent is 108 // already known. If the total blockscore of the newly inserted header becomes 109 // greater than the current known TD, the canonical chain is re-routed. 110 // 111 // Note: This method is not concurrent-safe with inserting blocks simultaneously 112 // into the chain, as side effects caused by reorganisations cannot be emulated 113 // without the real blocks. Hence, writing headers directly should only be done 114 // in two scenarios: pure-header mode of operation (light clients), or properly 115 // separated header/block phases (non-archive clients). 116 func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, err error) { 117 // Cache some values to prevent constant recalculation 118 var ( 119 hash = header.Hash() 120 number = header.Number.Uint64() 121 ) 122 // Calculate the total blockscore of the header 123 ptd := hc.GetTd(header.ParentHash, number-1) 124 if ptd == nil { 125 logger.Error("unknown ancestor (WriteHeader)", "num", number, 126 "hash", hash, "parentHash", header.ParentHash) 127 return NonStatTy, consensus.ErrUnknownAncestor 128 } 129 localTd := hc.GetTd(hc.currentHeaderHash, hc.CurrentHeader().Number.Uint64()) 130 externTd := new(big.Int).Add(header.BlockScore, ptd) 131 132 // Irrelevant of the canonical status, write the td and header to the database 133 hc.WriteTd(hash, number, externTd) 134 hc.chainDB.WriteHeader(header) 135 136 // TODO-Klaytn-Issue264 If we are using istanbul BFT, then we always have a canonical chain. 137 // Later we may be able to refine below code. 138 139 // If the total blockscore is higher than our known, add it to the canonical chain 140 // Second clause in the if statement reduces the vulnerability to selfish mining. 141 // Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf 142 if externTd.Cmp(localTd) > 0 || (externTd.Cmp(localTd) == 0 && mrand.Float64() < 0.5) { 143 // Delete any canonical number assignments above the new head 144 for i := number + 1; ; i++ { 145 hash := hc.chainDB.ReadCanonicalHash(i) 146 if hash == (common.Hash{}) { 147 break 148 } 149 hc.chainDB.DeleteCanonicalHash(i) 150 } 151 // Overwrite any stale canonical number assignments 152 var ( 153 headHash = header.ParentHash 154 headNumber = header.Number.Uint64() - 1 155 headHeader = hc.GetHeader(headHash, headNumber) 156 ) 157 for hc.chainDB.ReadCanonicalHash(headNumber) != headHash { 158 hc.chainDB.WriteCanonicalHash(headHash, headNumber) 159 160 headHash = headHeader.ParentHash 161 headNumber = headHeader.Number.Uint64() - 1 162 headHeader = hc.GetHeader(headHash, headNumber) 163 } 164 // Extend the canonical chain with the new header 165 hc.chainDB.WriteCanonicalHash(hash, number) 166 hc.chainDB.WriteHeadHeaderHash(hash) 167 168 hc.currentHeaderHash = hash 169 hc.currentHeader.Store(types.CopyHeader(header)) 170 171 status = CanonStatTy 172 } else { 173 status = SideStatTy 174 } 175 return 176 } 177 178 // WhCallback is a callback function for inserting individual headers. 179 // A callback is used for two reasons: first, in a LightChain, status should be 180 // processed and light chain events sent, while in a BlockChain this is not 181 // necessary since chain events are sent after inserting blocks. Second, the 182 // header writes should be protected by the parent chain mutex individually. 183 type WhCallback func(*types.Header) error 184 185 func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int) (int, error) { 186 // Do a sanity check that the provided chain is actually ordered and linked 187 for i := 1; i < len(chain); i++ { 188 if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() { 189 // Chain broke ancestry, log a messge (programming error) and skip insertion 190 logger.Error("Non contiguous header insert", "number", chain[i].Number, "hash", chain[i].Hash(), 191 "parent", chain[i].ParentHash, "prevnumber", chain[i-1].Number, "prevhash", chain[i-1].Hash()) 192 193 return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, chain[i-1].Number, 194 chain[i-1].Hash().Bytes()[:4], i, chain[i].Number, chain[i].Hash().Bytes()[:4], chain[i].ParentHash[:4]) 195 } 196 } 197 198 // Generate the list of seal verification requests, and start the parallel verifier 199 seals := make([]bool, len(chain)) 200 for i := 0; i < len(seals)/checkFreq; i++ { 201 index := i*checkFreq + hc.rand.Intn(checkFreq) 202 if index >= len(seals) { 203 index = len(seals) - 1 204 } 205 seals[index] = true 206 } 207 seals[len(seals)-1] = true // Last should always be verified to avoid junk 208 209 var ( 210 abort chan<- struct{} 211 results <-chan error 212 ) 213 if hc.engine.CanVerifyHeadersConcurrently() { 214 abort, results = hc.engine.VerifyHeaders(hc, chain, seals) 215 } else { 216 abort, results = hc.engine.PreprocessHeaderVerification(chain) 217 } 218 defer close(abort) 219 220 // Iterate over the headers and ensure they all check out 221 for i, header := range chain { 222 // If the chain is terminating, stop processing blocks 223 if hc.procInterrupt() { 224 logger.Debug("Premature abort during headers verification") 225 return 0, errors.New("aborted") 226 } 227 // If the header is a banned one, straight out abort 228 if BadHashes[header.Hash()] { 229 return i, ErrBlacklistedHash 230 } 231 // Otherwise wait for headers checks and ensure they pass 232 if err := <-results; err != nil { 233 return i, err 234 } 235 } 236 237 return 0, nil 238 } 239 240 // InsertHeaderChain attempts to insert the given header chain in to the local 241 // chain, possibly creating a reorg. If an error is returned, it will return the 242 // index number of the failing header as well an error describing what went wrong. 243 // 244 // The verify parameter can be used to fine tune whether nonce verification 245 // should be done or not. The reason behind the optional check is because some 246 // of the header retrieval mechanisms already need to verfy nonces, as well as 247 // because nonces can be verified sparsely, not needing to check each. 248 func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, writeHeader WhCallback, start time.Time) (int, error) { 249 // Collect some import statistics to report on 250 stats := struct{ processed, ignored int }{} 251 // All headers passed verification, import them into the database 252 for i, header := range chain { 253 // Short circuit insertion if shutting down 254 if hc.procInterrupt() { 255 logger.Debug("Premature abort during headers import") 256 return i, errors.New("aborted") 257 } 258 // If the header's already known, skip it, otherwise store 259 if hc.HasHeader(header.Hash(), header.Number.Uint64()) { 260 stats.ignored++ 261 continue 262 } 263 if !hc.engine.CanVerifyHeadersConcurrently() { 264 if err := hc.engine.VerifyHeader(hc, header, true); err != nil { 265 return i, err 266 } 267 } 268 if err := writeHeader(header); err != nil { 269 return i, err 270 } 271 stats.processed++ 272 } 273 // Report some public statistics so the user has a clue what's going on 274 last := chain[len(chain)-1] 275 logger.Info("Imported new block headers", "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)), 276 "number", last.Number, "hash", last.Hash(), "ignored", stats.ignored) 277 278 return 0, nil 279 } 280 281 // GetBlockHashesFromHash retrieves a number of block hashes starting at a given 282 // hash, fetching towards the genesis block. 283 func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash { 284 // Get the origin header from which to fetch 285 header := hc.GetHeaderByHash(hash) 286 if header == nil { 287 return nil 288 } 289 // Iterate the headers until enough is collected or the genesis reached 290 chain := make([]common.Hash, 0, max) 291 for i := uint64(0); i < max; i++ { 292 next := header.ParentHash 293 if header = hc.GetHeader(next, header.Number.Uint64()-1); header == nil { 294 break 295 } 296 chain = append(chain, next) 297 if header.Number.Sign() == 0 { 298 break 299 } 300 } 301 return chain 302 } 303 304 // GetTd retrieves a block's total blockscore in the canonical chain from the 305 // database by hash and number, caching it if found. 306 func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int { 307 return hc.chainDB.ReadTd(hash, number) 308 } 309 310 // GetTdByHash retrieves a block's total blockscore in the canonical chain from the 311 // database by hash, caching it if found. 312 func (hc *HeaderChain) GetTdByHash(hash common.Hash) *big.Int { 313 number := hc.GetBlockNumber(hash) 314 if number == nil { 315 return nil 316 } 317 return hc.GetTd(hash, *number) 318 } 319 320 // WriteTd stores a block's total blockscore into the database, also caching it 321 // along the way. 322 func (hc *HeaderChain) WriteTd(hash common.Hash, number uint64, td *big.Int) { 323 hc.chainDB.WriteTd(hash, number, td) 324 } 325 326 // GetHeader retrieves a block header from the database by hash and number, 327 // caching it if found. 328 func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header { 329 return hc.chainDB.ReadHeader(hash, number) 330 } 331 332 // GetHeaderByHash retrieves a block header from the database by hash, caching it if 333 // found. 334 func (hc *HeaderChain) GetHeaderByHash(hash common.Hash) *types.Header { 335 number := hc.GetBlockNumber(hash) 336 if number == nil { 337 return nil 338 } 339 return hc.GetHeader(hash, *number) 340 } 341 342 // HasHeader checks if a block header is present in the database or not. 343 func (hc *HeaderChain) HasHeader(hash common.Hash, number uint64) bool { 344 return hc.chainDB.HasHeader(hash, number) 345 } 346 347 // GetHeaderByNumber retrieves a block header from the database by number, 348 // caching it (associated with its hash) if found. 349 func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header { 350 hash := hc.chainDB.ReadCanonicalHash(number) 351 if hash == (common.Hash{}) { 352 return nil 353 } 354 return hc.GetHeader(hash, number) 355 } 356 357 // CurrentHeader retrieves the current head header of the canonical chain. The 358 // header is retrieved from the HeaderChain's internal cache. 359 func (hc *HeaderChain) CurrentHeader() *types.Header { 360 return hc.currentHeader.Load().(*types.Header) 361 } 362 363 // CurrentBlock is added because HeaderChain is sometimes used as 364 // type consensus.ChainReader and consensus.ChainReader interface has CurrentBlock. 365 // However CurrentBlock is not supported in HeaderChain so this function just panics. 366 func (hc *HeaderChain) CurrentBlock() *types.Block { 367 panic("CurrentBlock not supported for HeaderChain") 368 } 369 370 // SetCurrentHeader sets the current head header of the canonical chain. 371 func (hc *HeaderChain) SetCurrentHeader(head *types.Header) { 372 hc.chainDB.WriteHeadHeaderHash(head.Hash()) 373 374 hc.currentHeader.Store(head) 375 hc.currentHeaderHash = head.Hash() 376 } 377 378 type ( 379 // UpdateHeadBlocksCallback is a callback function that is called by SetHead 380 // before head header is updated. The method will return the actual block it 381 // updated the head to (missing state) and a flag if setHead should continue 382 // rewinding till that forcefully (exceeded ancient limits) 383 UpdateHeadBlocksCallback func(*types.Header) (uint64, error) 384 385 // DeleteBlockContentCallback is a callback function that is called by SetHead 386 // before each header is deleted. 387 DeleteBlockContentCallback func(common.Hash, uint64) 388 ) 389 390 func (hc *HeaderChain) SetHead(head uint64, updateFn UpdateHeadBlocksCallback, delFn DeleteBlockContentCallback) error { 391 var parentHash common.Hash 392 for hdr := hc.CurrentHeader(); hdr != nil && hdr.Number.Uint64() > head; hdr = hc.CurrentHeader() { 393 hash, num := hdr.Hash(), hdr.Number.Uint64() 394 395 // Rewind block chain to new head. 396 parent := hc.GetHeader(hdr.ParentHash, num-1) 397 if parent == nil { 398 parent = hc.genesisHeader 399 } 400 parentHash = parent.Hash() 401 402 // Notably, since Klaytn has the possibility for setting the head to a low 403 // height which is even lower than ancient head. 404 // In order to ensure that the head is always no higher than the data in 405 // the database (ancient store or active store), we need to update head 406 // first then remove the relative data from the database. 407 // 408 // Update head first(head fast block, head full block) before deleting the data. 409 if updateFn != nil { 410 latestBlkNum, err := updateFn(parent) 411 if err != nil { 412 return err 413 } 414 if latestBlkNum < head { 415 // Discrepancy of loop iteration occurs. blockchain sets the 416 // current block number to `latestBlkNum`. Remove further blocks accordingly 417 head = latestBlkNum 418 } 419 } 420 // Update head header then. 421 hc.chainDB.WriteHeadHeaderHash(parentHash) 422 423 // Remove the related data from the database on all sidechains 424 if delFn != nil { 425 delFn(hash, num) 426 } 427 428 // Rewind header chain to new head. 429 hc.chainDB.DeleteHeader(hash, num) 430 hc.chainDB.DeleteTd(hash, num) 431 hc.chainDB.DeleteCanonicalHash(num) 432 433 hc.currentHeader.Store(parent) 434 hc.currentHeaderHash = parentHash 435 } 436 437 // Clear out any stale content from the caches 438 hc.chainDB.ClearHeaderChainCache() 439 return nil 440 } 441 442 // SetGenesis sets a new genesis block header for the chain 443 func (hc *HeaderChain) SetGenesis(head *types.Header) { 444 hc.genesisHeader = head 445 } 446 447 // Config retrieves the header chain's chain configuration. 448 func (hc *HeaderChain) Config() *params.ChainConfig { return hc.config } 449 450 // Engine retrieves the header chain's consensus engine. 451 func (hc *HeaderChain) Engine() consensus.Engine { return hc.engine } 452 453 // GetBlock implements consensus.ChainReader, and returns nil for every input as 454 // a header chain does not have blocks available for retrieval. 455 func (hc *HeaderChain) GetBlock(hash common.Hash, number uint64) *types.Block { 456 return nil 457 } 458 459 func (hc *HeaderChain) State() (*state.StateDB, error) { 460 return nil, errors.New("HeaderChain does not support State() method") 461 } 462 463 func (hc *HeaderChain) StateAt(root common.Hash) (*state.StateDB, error) { 464 return nil, errors.New("HeaderChain does not support StateAt() method") 465 }