github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/core/database_util.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 package core 13 14 import ( 15 "bytes" 16 "encoding/binary" 17 "encoding/json" 18 "errors" 19 "fmt" 20 "math/big" 21 22 "github.com/Sberex/go-sberex/common" 23 "github.com/Sberex/go-sberex/core/types" 24 "github.com/Sberex/go-sberex/ethdb" 25 "github.com/Sberex/go-sberex/log" 26 "github.com/Sberex/go-sberex/metrics" 27 "github.com/Sberex/go-sberex/params" 28 "github.com/Sberex/go-sberex/rlp" 29 ) 30 31 // DatabaseReader wraps the Get method of a backing data store. 32 type DatabaseReader interface { 33 Get(key []byte) (value []byte, err error) 34 } 35 36 // DatabaseDeleter wraps the Delete method of a backing data store. 37 type DatabaseDeleter interface { 38 Delete(key []byte) error 39 } 40 41 var ( 42 headHeaderKey = []byte("LastHeader") 43 headBlockKey = []byte("LastBlock") 44 headFastKey = []byte("LastFast") 45 46 // Data item prefixes (use single byte to avoid mixing data types, avoid `i`). 47 headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header 48 tdSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + tdSuffix -> td 49 numSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + numSuffix -> hash 50 blockHashPrefix = []byte("H") // blockHashPrefix + hash -> num (uint64 big endian) 51 bodyPrefix = []byte("b") // bodyPrefix + num (uint64 big endian) + hash -> block body 52 blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts 53 lookupPrefix = []byte("l") // lookupPrefix + hash -> transaction/receipt lookup metadata 54 bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits 55 56 preimagePrefix = "secure-key-" // preimagePrefix + hash -> preimage 57 configPrefix = []byte("sberex-config-") // config prefix for the db 58 59 // Chain index prefixes (use `i` + single byte to avoid mixing data types). 60 BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress 61 62 // used by old db, now only used for conversion 63 oldReceiptsPrefix = []byte("receipts-") 64 oldTxMetaSuffix = []byte{0x01} 65 66 ErrChainConfigNotFound = errors.New("ChainConfig not found") // general config not found error 67 68 preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) 69 preimageHitCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) 70 ) 71 72 // TxLookupEntry is a positional metadata to help looking up the data content of 73 // a transaction or receipt given only its hash. 74 type TxLookupEntry struct { 75 BlockHash common.Hash 76 BlockIndex uint64 77 Index uint64 78 } 79 80 // encodeBlockNumber encodes a block number as big endian uint64 81 func encodeBlockNumber(number uint64) []byte { 82 enc := make([]byte, 8) 83 binary.BigEndian.PutUint64(enc, number) 84 return enc 85 } 86 87 // GetCanonicalHash retrieves a hash assigned to a canonical block number. 88 func GetCanonicalHash(db DatabaseReader, number uint64) common.Hash { 89 data, _ := db.Get(append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...)) 90 if len(data) == 0 { 91 return common.Hash{} 92 } 93 return common.BytesToHash(data) 94 } 95 96 // missingNumber is returned by GetBlockNumber if no header with the 97 // given block hash has been stored in the database 98 const missingNumber = uint64(0xffffffffffffffff) 99 100 // GetBlockNumber returns the block number assigned to a block hash 101 // if the corresponding header is present in the database 102 func GetBlockNumber(db DatabaseReader, hash common.Hash) uint64 { 103 data, _ := db.Get(append(blockHashPrefix, hash.Bytes()...)) 104 if len(data) != 8 { 105 return missingNumber 106 } 107 return binary.BigEndian.Uint64(data) 108 } 109 110 // GetHeadHeaderHash retrieves the hash of the current canonical head block's 111 // header. The difference between this and GetHeadBlockHash is that whereas the 112 // last block hash is only updated upon a full block import, the last header 113 // hash is updated already at header import, allowing head tracking for the 114 // light synchronization mechanism. 115 func GetHeadHeaderHash(db DatabaseReader) common.Hash { 116 data, _ := db.Get(headHeaderKey) 117 if len(data) == 0 { 118 return common.Hash{} 119 } 120 return common.BytesToHash(data) 121 } 122 123 // GetHeadBlockHash retrieves the hash of the current canonical head block. 124 func GetHeadBlockHash(db DatabaseReader) common.Hash { 125 data, _ := db.Get(headBlockKey) 126 if len(data) == 0 { 127 return common.Hash{} 128 } 129 return common.BytesToHash(data) 130 } 131 132 // GetHeadFastBlockHash retrieves the hash of the current canonical head block during 133 // fast synchronization. The difference between this and GetHeadBlockHash is that 134 // whereas the last block hash is only updated upon a full block import, the last 135 // fast hash is updated when importing pre-processed blocks. 136 func GetHeadFastBlockHash(db DatabaseReader) common.Hash { 137 data, _ := db.Get(headFastKey) 138 if len(data) == 0 { 139 return common.Hash{} 140 } 141 return common.BytesToHash(data) 142 } 143 144 // GetHeaderRLP retrieves a block header in its raw RLP database encoding, or nil 145 // if the header's not found. 146 func GetHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue { 147 data, _ := db.Get(headerKey(hash, number)) 148 return data 149 } 150 151 // GetHeader retrieves the block header corresponding to the hash, nil if none 152 // found. 153 func GetHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Header { 154 data := GetHeaderRLP(db, hash, number) 155 if len(data) == 0 { 156 return nil 157 } 158 header := new(types.Header) 159 if err := rlp.Decode(bytes.NewReader(data), header); err != nil { 160 log.Error("Invalid block header RLP", "hash", hash, "err", err) 161 return nil 162 } 163 return header 164 } 165 166 // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. 167 func GetBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue { 168 data, _ := db.Get(blockBodyKey(hash, number)) 169 return data 170 } 171 172 func headerKey(hash common.Hash, number uint64) []byte { 173 return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...) 174 } 175 176 func blockBodyKey(hash common.Hash, number uint64) []byte { 177 return append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...) 178 } 179 180 // GetBody retrieves the block body (transactons, uncles) corresponding to the 181 // hash, nil if none found. 182 func GetBody(db DatabaseReader, hash common.Hash, number uint64) *types.Body { 183 data := GetBodyRLP(db, hash, number) 184 if len(data) == 0 { 185 return nil 186 } 187 body := new(types.Body) 188 if err := rlp.Decode(bytes.NewReader(data), body); err != nil { 189 log.Error("Invalid block body RLP", "hash", hash, "err", err) 190 return nil 191 } 192 return body 193 } 194 195 // GetTd retrieves a block's total difficulty corresponding to the hash, nil if 196 // none found. 197 func GetTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int { 198 data, _ := db.Get(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash[:]...), tdSuffix...)) 199 if len(data) == 0 { 200 return nil 201 } 202 td := new(big.Int) 203 if err := rlp.Decode(bytes.NewReader(data), td); err != nil { 204 log.Error("Invalid block total difficulty RLP", "hash", hash, "err", err) 205 return nil 206 } 207 return td 208 } 209 210 // GetBlock retrieves an entire block corresponding to the hash, assembling it 211 // back from the stored header and body. If either the header or body could not 212 // be retrieved nil is returned. 213 // 214 // Note, due to concurrent download of header and block body the header and thus 215 // canonical hash can be stored in the database but the body data not (yet). 216 func GetBlock(db DatabaseReader, hash common.Hash, number uint64) *types.Block { 217 // Retrieve the block header and body contents 218 header := GetHeader(db, hash, number) 219 if header == nil { 220 return nil 221 } 222 body := GetBody(db, hash, number) 223 if body == nil { 224 return nil 225 } 226 // Reassemble the block and return 227 return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles) 228 } 229 230 // GetBlockReceipts retrieves the receipts generated by the transactions included 231 // in a block given by its hash. 232 func GetBlockReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts { 233 data, _ := db.Get(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash[:]...)) 234 if len(data) == 0 { 235 return nil 236 } 237 storageReceipts := []*types.ReceiptForStorage{} 238 if err := rlp.DecodeBytes(data, &storageReceipts); err != nil { 239 log.Error("Invalid receipt array RLP", "hash", hash, "err", err) 240 return nil 241 } 242 receipts := make(types.Receipts, len(storageReceipts)) 243 for i, receipt := range storageReceipts { 244 receipts[i] = (*types.Receipt)(receipt) 245 } 246 return receipts 247 } 248 249 // GetTxLookupEntry retrieves the positional metadata associated with a transaction 250 // hash to allow retrieving the transaction or receipt by hash. 251 func GetTxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64, uint64) { 252 // Load the positional metadata from disk and bail if it fails 253 data, _ := db.Get(append(lookupPrefix, hash.Bytes()...)) 254 if len(data) == 0 { 255 return common.Hash{}, 0, 0 256 } 257 // Parse and return the contents of the lookup entry 258 var entry TxLookupEntry 259 if err := rlp.DecodeBytes(data, &entry); err != nil { 260 log.Error("Invalid lookup entry RLP", "hash", hash, "err", err) 261 return common.Hash{}, 0, 0 262 } 263 return entry.BlockHash, entry.BlockIndex, entry.Index 264 } 265 266 // GetTransaction retrieves a specific transaction from the database, along with 267 // its added positional metadata. 268 func GetTransaction(db DatabaseReader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) { 269 // Retrieve the lookup metadata and resolve the transaction from the body 270 blockHash, blockNumber, txIndex := GetTxLookupEntry(db, hash) 271 272 if blockHash != (common.Hash{}) { 273 body := GetBody(db, blockHash, blockNumber) 274 if body == nil || len(body.Transactions) <= int(txIndex) { 275 log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash, "index", txIndex) 276 return nil, common.Hash{}, 0, 0 277 } 278 return body.Transactions[txIndex], blockHash, blockNumber, txIndex 279 } 280 // Old transaction representation, load the transaction and it's metadata separately 281 data, _ := db.Get(hash.Bytes()) 282 if len(data) == 0 { 283 return nil, common.Hash{}, 0, 0 284 } 285 var tx types.Transaction 286 if err := rlp.DecodeBytes(data, &tx); err != nil { 287 return nil, common.Hash{}, 0, 0 288 } 289 // Retrieve the blockchain positional metadata 290 data, _ = db.Get(append(hash.Bytes(), oldTxMetaSuffix...)) 291 if len(data) == 0 { 292 return nil, common.Hash{}, 0, 0 293 } 294 var entry TxLookupEntry 295 if err := rlp.DecodeBytes(data, &entry); err != nil { 296 return nil, common.Hash{}, 0, 0 297 } 298 return &tx, entry.BlockHash, entry.BlockIndex, entry.Index 299 } 300 301 // GetReceipt retrieves a specific transaction receipt from the database, along with 302 // its added positional metadata. 303 func GetReceipt(db DatabaseReader, hash common.Hash) (*types.Receipt, common.Hash, uint64, uint64) { 304 // Retrieve the lookup metadata and resolve the receipt from the receipts 305 blockHash, blockNumber, receiptIndex := GetTxLookupEntry(db, hash) 306 307 if blockHash != (common.Hash{}) { 308 receipts := GetBlockReceipts(db, blockHash, blockNumber) 309 if len(receipts) <= int(receiptIndex) { 310 log.Error("Receipt refereced missing", "number", blockNumber, "hash", blockHash, "index", receiptIndex) 311 return nil, common.Hash{}, 0, 0 312 } 313 return receipts[receiptIndex], blockHash, blockNumber, receiptIndex 314 } 315 // Old receipt representation, load the receipt and set an unknown metadata 316 data, _ := db.Get(append(oldReceiptsPrefix, hash[:]...)) 317 if len(data) == 0 { 318 return nil, common.Hash{}, 0, 0 319 } 320 var receipt types.ReceiptForStorage 321 err := rlp.DecodeBytes(data, &receipt) 322 if err != nil { 323 log.Error("Invalid receipt RLP", "hash", hash, "err", err) 324 } 325 return (*types.Receipt)(&receipt), common.Hash{}, 0, 0 326 } 327 328 // GetBloomBits retrieves the compressed bloom bit vector belonging to the given 329 // section and bit index from the. 330 func GetBloomBits(db DatabaseReader, bit uint, section uint64, head common.Hash) ([]byte, error) { 331 key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...) 332 333 binary.BigEndian.PutUint16(key[1:], uint16(bit)) 334 binary.BigEndian.PutUint64(key[3:], section) 335 336 return db.Get(key) 337 } 338 339 // WriteCanonicalHash stores the canonical hash for the given block number. 340 func WriteCanonicalHash(db ethdb.Putter, hash common.Hash, number uint64) error { 341 key := append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...) 342 if err := db.Put(key, hash.Bytes()); err != nil { 343 log.Crit("Failed to store number to hash mapping", "err", err) 344 } 345 return nil 346 } 347 348 // WriteHeadHeaderHash stores the head header's hash. 349 func WriteHeadHeaderHash(db ethdb.Putter, hash common.Hash) error { 350 if err := db.Put(headHeaderKey, hash.Bytes()); err != nil { 351 log.Crit("Failed to store last header's hash", "err", err) 352 } 353 return nil 354 } 355 356 // WriteHeadBlockHash stores the head block's hash. 357 func WriteHeadBlockHash(db ethdb.Putter, hash common.Hash) error { 358 if err := db.Put(headBlockKey, hash.Bytes()); err != nil { 359 log.Crit("Failed to store last block's hash", "err", err) 360 } 361 return nil 362 } 363 364 // WriteHeadFastBlockHash stores the fast head block's hash. 365 func WriteHeadFastBlockHash(db ethdb.Putter, hash common.Hash) error { 366 if err := db.Put(headFastKey, hash.Bytes()); err != nil { 367 log.Crit("Failed to store last fast block's hash", "err", err) 368 } 369 return nil 370 } 371 372 // WriteHeader serializes a block header into the database. 373 func WriteHeader(db ethdb.Putter, header *types.Header) error { 374 data, err := rlp.EncodeToBytes(header) 375 if err != nil { 376 return err 377 } 378 hash := header.Hash().Bytes() 379 num := header.Number.Uint64() 380 encNum := encodeBlockNumber(num) 381 key := append(blockHashPrefix, hash...) 382 if err := db.Put(key, encNum); err != nil { 383 log.Crit("Failed to store hash to number mapping", "err", err) 384 } 385 key = append(append(headerPrefix, encNum...), hash...) 386 if err := db.Put(key, data); err != nil { 387 log.Crit("Failed to store header", "err", err) 388 } 389 return nil 390 } 391 392 // WriteBody serializes the body of a block into the database. 393 func WriteBody(db ethdb.Putter, hash common.Hash, number uint64, body *types.Body) error { 394 data, err := rlp.EncodeToBytes(body) 395 if err != nil { 396 return err 397 } 398 return WriteBodyRLP(db, hash, number, data) 399 } 400 401 // WriteBodyRLP writes a serialized body of a block into the database. 402 func WriteBodyRLP(db ethdb.Putter, hash common.Hash, number uint64, rlp rlp.RawValue) error { 403 key := append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...) 404 if err := db.Put(key, rlp); err != nil { 405 log.Crit("Failed to store block body", "err", err) 406 } 407 return nil 408 } 409 410 // WriteTd serializes the total difficulty of a block into the database. 411 func WriteTd(db ethdb.Putter, hash common.Hash, number uint64, td *big.Int) error { 412 data, err := rlp.EncodeToBytes(td) 413 if err != nil { 414 return err 415 } 416 key := append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), tdSuffix...) 417 if err := db.Put(key, data); err != nil { 418 log.Crit("Failed to store block total difficulty", "err", err) 419 } 420 return nil 421 } 422 423 // WriteBlock serializes a block into the database, header and body separately. 424 func WriteBlock(db ethdb.Putter, block *types.Block) error { 425 // Store the body first to retain database consistency 426 if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil { 427 return err 428 } 429 // Store the header too, signaling full block ownership 430 if err := WriteHeader(db, block.Header()); err != nil { 431 return err 432 } 433 return nil 434 } 435 436 // WriteBlockReceipts stores all the transaction receipts belonging to a block 437 // as a single receipt slice. This is used during chain reorganisations for 438 // rescheduling dropped transactions. 439 func WriteBlockReceipts(db ethdb.Putter, hash common.Hash, number uint64, receipts types.Receipts) error { 440 // Convert the receipts into their storage form and serialize them 441 storageReceipts := make([]*types.ReceiptForStorage, len(receipts)) 442 for i, receipt := range receipts { 443 storageReceipts[i] = (*types.ReceiptForStorage)(receipt) 444 } 445 bytes, err := rlp.EncodeToBytes(storageReceipts) 446 if err != nil { 447 return err 448 } 449 // Store the flattened receipt slice 450 key := append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...) 451 if err := db.Put(key, bytes); err != nil { 452 log.Crit("Failed to store block receipts", "err", err) 453 } 454 return nil 455 } 456 457 // WriteTxLookupEntries stores a positional metadata for every transaction from 458 // a block, enabling hash based transaction and receipt lookups. 459 func WriteTxLookupEntries(db ethdb.Putter, block *types.Block) error { 460 // Iterate over each transaction and encode its metadata 461 for i, tx := range block.Transactions() { 462 entry := TxLookupEntry{ 463 BlockHash: block.Hash(), 464 BlockIndex: block.NumberU64(), 465 Index: uint64(i), 466 } 467 data, err := rlp.EncodeToBytes(entry) 468 if err != nil { 469 return err 470 } 471 if err := db.Put(append(lookupPrefix, tx.Hash().Bytes()...), data); err != nil { 472 return err 473 } 474 } 475 return nil 476 } 477 478 // WriteBloomBits writes the compressed bloom bits vector belonging to the given 479 // section and bit index. 480 func WriteBloomBits(db ethdb.Putter, bit uint, section uint64, head common.Hash, bits []byte) { 481 key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...) 482 483 binary.BigEndian.PutUint16(key[1:], uint16(bit)) 484 binary.BigEndian.PutUint64(key[3:], section) 485 486 if err := db.Put(key, bits); err != nil { 487 log.Crit("Failed to store bloom bits", "err", err) 488 } 489 } 490 491 // DeleteCanonicalHash removes the number to hash canonical mapping. 492 func DeleteCanonicalHash(db DatabaseDeleter, number uint64) { 493 db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...)) 494 } 495 496 // DeleteHeader removes all block header data associated with a hash. 497 func DeleteHeader(db DatabaseDeleter, hash common.Hash, number uint64) { 498 db.Delete(append(blockHashPrefix, hash.Bytes()...)) 499 db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)) 500 } 501 502 // DeleteBody removes all block body data associated with a hash. 503 func DeleteBody(db DatabaseDeleter, hash common.Hash, number uint64) { 504 db.Delete(append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)) 505 } 506 507 // DeleteTd removes all block total difficulty data associated with a hash. 508 func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) { 509 db.Delete(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), tdSuffix...)) 510 } 511 512 // DeleteBlock removes all block data associated with a hash. 513 func DeleteBlock(db DatabaseDeleter, hash common.Hash, number uint64) { 514 DeleteBlockReceipts(db, hash, number) 515 DeleteHeader(db, hash, number) 516 DeleteBody(db, hash, number) 517 DeleteTd(db, hash, number) 518 } 519 520 // DeleteBlockReceipts removes all receipt data associated with a block hash. 521 func DeleteBlockReceipts(db DatabaseDeleter, hash common.Hash, number uint64) { 522 db.Delete(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)) 523 } 524 525 // DeleteTxLookupEntry removes all transaction data associated with a hash. 526 func DeleteTxLookupEntry(db DatabaseDeleter, hash common.Hash) { 527 db.Delete(append(lookupPrefix, hash.Bytes()...)) 528 } 529 530 // PreimageTable returns a Database instance with the key prefix for preimage entries. 531 func PreimageTable(db ethdb.Database) ethdb.Database { 532 return ethdb.NewTable(db, preimagePrefix) 533 } 534 535 // WritePreimages writes the provided set of preimages to the database. `number` is the 536 // current block number, and is used for debug messages only. 537 func WritePreimages(db ethdb.Database, number uint64, preimages map[common.Hash][]byte) error { 538 table := PreimageTable(db) 539 batch := table.NewBatch() 540 hitCount := 0 541 for hash, preimage := range preimages { 542 if _, err := table.Get(hash.Bytes()); err != nil { 543 batch.Put(hash.Bytes(), preimage) 544 hitCount++ 545 } 546 } 547 preimageCounter.Inc(int64(len(preimages))) 548 preimageHitCounter.Inc(int64(hitCount)) 549 if hitCount > 0 { 550 if err := batch.Write(); err != nil { 551 return fmt.Errorf("preimage write fail for block %d: %v", number, err) 552 } 553 } 554 return nil 555 } 556 557 // GetBlockChainVersion reads the version number from db. 558 func GetBlockChainVersion(db DatabaseReader) int { 559 var vsn uint 560 enc, _ := db.Get([]byte("BlockchainVersion")) 561 rlp.DecodeBytes(enc, &vsn) 562 return int(vsn) 563 } 564 565 // WriteBlockChainVersion writes vsn as the version number to db. 566 func WriteBlockChainVersion(db ethdb.Putter, vsn int) { 567 enc, _ := rlp.EncodeToBytes(uint(vsn)) 568 db.Put([]byte("BlockchainVersion"), enc) 569 } 570 571 // WriteChainConfig writes the chain config settings to the database. 572 func WriteChainConfig(db ethdb.Putter, hash common.Hash, cfg *params.ChainConfig) error { 573 // short circuit and ignore if nil config. GetChainConfig 574 // will return a default. 575 if cfg == nil { 576 return nil 577 } 578 579 jsonChainConfig, err := json.Marshal(cfg) 580 if err != nil { 581 return err 582 } 583 584 return db.Put(append(configPrefix, hash[:]...), jsonChainConfig) 585 } 586 587 // GetChainConfig will fetch the network settings based on the given hash. 588 func GetChainConfig(db DatabaseReader, hash common.Hash) (*params.ChainConfig, error) { 589 jsonChainConfig, _ := db.Get(append(configPrefix, hash[:]...)) 590 if len(jsonChainConfig) == 0 { 591 return nil, ErrChainConfigNotFound 592 } 593 594 var config params.ChainConfig 595 if err := json.Unmarshal(jsonChainConfig, &config); err != nil { 596 return nil, err 597 } 598 599 return &config, nil 600 } 601 602 // FindCommonAncestor returns the last common ancestor of two block headers 603 func FindCommonAncestor(db DatabaseReader, a, b *types.Header) *types.Header { 604 for bn := b.Number.Uint64(); a.Number.Uint64() > bn; { 605 a = GetHeader(db, a.ParentHash, a.Number.Uint64()-1) 606 if a == nil { 607 return nil 608 } 609 } 610 for an := a.Number.Uint64(); an < b.Number.Uint64(); { 611 b = GetHeader(db, b.ParentHash, b.Number.Uint64()-1) 612 if b == nil { 613 return nil 614 } 615 } 616 for a.Hash() != b.Hash() { 617 a = GetHeader(db, a.ParentHash, a.Number.Uint64()-1) 618 if a == nil { 619 return nil 620 } 621 b = GetHeader(db, b.ParentHash, b.Number.Uint64()-1) 622 if b == nil { 623 return nil 624 } 625 } 626 return a 627 }