github.com/core-coin/go-core/v2@v2.1.9/core/rawdb/accessors_chain.go (about) 1 // Copyright 2018 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package rawdb 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "math/big" 23 24 "github.com/core-coin/go-core/v2/xcbdb" 25 26 "github.com/core-coin/go-core/v2/common" 27 "github.com/core-coin/go-core/v2/core/types" 28 "github.com/core-coin/go-core/v2/crypto" 29 "github.com/core-coin/go-core/v2/log" 30 "github.com/core-coin/go-core/v2/params" 31 "github.com/core-coin/go-core/v2/rlp" 32 ) 33 34 // ReadCanonicalHash retrieves the hash assigned to a canonical block number. 35 func ReadCanonicalHash(db xcbdb.Reader, number uint64) common.Hash { 36 data, _ := db.Ancient(freezerHashTable, number) 37 if len(data) == 0 { 38 data, _ = db.Get(headerHashKey(number)) 39 // In the background freezer is moving data from leveldb to flatten files. 40 // So during the first check for ancient db, the data is not yet in there, 41 // but when we reach into leveldb, the data was already moved. That would 42 // result in a not found error. 43 if len(data) == 0 { 44 data, _ = db.Ancient(freezerHashTable, number) 45 } 46 } 47 if len(data) == 0 { 48 return common.Hash{} 49 } 50 return common.BytesToHash(data) 51 } 52 53 // WriteCanonicalHash stores the hash assigned to a canonical block number. 54 func WriteCanonicalHash(db xcbdb.KeyValueWriter, hash common.Hash, number uint64) { 55 if err := db.Put(headerHashKey(number), hash.Bytes()); err != nil { 56 log.Crit("Failed to store number to hash mapping", "err", err) 57 } 58 } 59 60 // DeleteCanonicalHash removes the number to hash canonical mapping. 61 func DeleteCanonicalHash(db xcbdb.KeyValueWriter, number uint64) { 62 if err := db.Delete(headerHashKey(number)); err != nil { 63 log.Crit("Failed to delete number to hash mapping", "err", err) 64 } 65 } 66 67 // ReadAllHashes retrieves all the hashes assigned to blocks at a certain heights, 68 // both canonical and reorged forks included. 69 func ReadAllHashes(db xcbdb.Iteratee, number uint64) []common.Hash { 70 prefix := headerKeyPrefix(number) 71 72 hashes := make([]common.Hash, 0, 1) 73 it := db.NewIterator(prefix, nil) 74 defer it.Release() 75 76 for it.Next() { 77 if key := it.Key(); len(key) == len(prefix)+32 { 78 hashes = append(hashes, common.BytesToHash(key[len(key)-32:])) 79 } 80 } 81 return hashes 82 } 83 84 // ReadAllCanonicalHashes retrieves all canonical number and hash mappings at the 85 // certain chain range. If the accumulated entries reaches the given threshold, 86 // abort the iteration and return the semi-finish result. 87 func ReadAllCanonicalHashes(db xcbdb.Iteratee, from uint64, to uint64, limit int) ([]uint64, []common.Hash) { 88 // Short circuit if the limit is 0. 89 if limit == 0 { 90 return nil, nil 91 } 92 var ( 93 numbers []uint64 94 hashes []common.Hash 95 ) 96 // Construct the key prefix of start point. 97 start, end := headerHashKey(from), headerHashKey(to) 98 it := db.NewIterator(nil, start) 99 defer it.Release() 100 101 for it.Next() { 102 if bytes.Compare(it.Key(), end) >= 0 { 103 break 104 } 105 if key := it.Key(); len(key) == len(headerPrefix)+8+1 && bytes.Equal(key[len(key)-1:], headerHashSuffix) { 106 numbers = append(numbers, binary.BigEndian.Uint64(key[len(headerPrefix):len(headerPrefix)+8])) 107 hashes = append(hashes, common.BytesToHash(it.Value())) 108 // If the accumulated entries reaches the limit threshold, return. 109 if len(numbers) >= limit { 110 break 111 } 112 } 113 } 114 return numbers, hashes 115 } 116 117 // ReadHeaderNumber returns the header number assigned to a hash. 118 func ReadHeaderNumber(db xcbdb.KeyValueReader, hash common.Hash) *uint64 { 119 data, _ := db.Get(headerNumberKey(hash)) 120 if len(data) != 8 { 121 return nil 122 } 123 number := binary.BigEndian.Uint64(data) 124 return &number 125 } 126 127 // WriteHeaderNumber stores the hash->number mapping. 128 func WriteHeaderNumber(db xcbdb.KeyValueWriter, hash common.Hash, number uint64) { 129 key := headerNumberKey(hash) 130 enc := encodeBlockNumber(number) 131 if err := db.Put(key, enc); err != nil { 132 log.Crit("Failed to store hash to number mapping", "err", err) 133 } 134 } 135 136 // DeleteHeaderNumber removes hash->number mapping. 137 func DeleteHeaderNumber(db xcbdb.KeyValueWriter, hash common.Hash) { 138 if err := db.Delete(headerNumberKey(hash)); err != nil { 139 log.Crit("Failed to delete hash to number mapping", "err", err) 140 } 141 } 142 143 // ReadHeadHeaderHash retrieves the hash of the current canonical head header. 144 func ReadHeadHeaderHash(db xcbdb.KeyValueReader) common.Hash { 145 data, _ := db.Get(headHeaderKey) 146 if len(data) == 0 { 147 return common.Hash{} 148 } 149 return common.BytesToHash(data) 150 } 151 152 // WriteHeadHeaderHash stores the hash of the current canonical head header. 153 func WriteHeadHeaderHash(db xcbdb.KeyValueWriter, hash common.Hash) { 154 if err := db.Put(headHeaderKey, hash.Bytes()); err != nil { 155 log.Crit("Failed to store last header's hash", "err", err) 156 } 157 } 158 159 // ReadHeadBlockHash retrieves the hash of the current canonical head block. 160 func ReadHeadBlockHash(db xcbdb.KeyValueReader) common.Hash { 161 data, _ := db.Get(headBlockKey) 162 if len(data) == 0 { 163 return common.Hash{} 164 } 165 return common.BytesToHash(data) 166 } 167 168 // WriteHeadBlockHash stores the head block's hash. 169 func WriteHeadBlockHash(db xcbdb.KeyValueWriter, hash common.Hash) { 170 if err := db.Put(headBlockKey, hash.Bytes()); err != nil { 171 log.Crit("Failed to store last block's hash", "err", err) 172 } 173 } 174 175 // ReadHeadFastBlockHash retrieves the hash of the current fast-sync head block. 176 func ReadHeadFastBlockHash(db xcbdb.KeyValueReader) common.Hash { 177 data, _ := db.Get(headFastBlockKey) 178 if len(data) == 0 { 179 return common.Hash{} 180 } 181 return common.BytesToHash(data) 182 } 183 184 // WriteHeadFastBlockHash stores the hash of the current fast-sync head block. 185 func WriteHeadFastBlockHash(db xcbdb.KeyValueWriter, hash common.Hash) { 186 if err := db.Put(headFastBlockKey, hash.Bytes()); err != nil { 187 log.Crit("Failed to store last fast block's hash", "err", err) 188 } 189 } 190 191 // ReadLastPivotNumber retrieves the number of the last pivot block. If the node 192 // full synced, the last pivot will always be nil. 193 func ReadLastPivotNumber(db xcbdb.KeyValueReader) *uint64 { 194 data, _ := db.Get(lastPivotKey) 195 if len(data) == 0 { 196 return nil 197 } 198 var pivot uint64 199 if err := rlp.DecodeBytes(data, &pivot); err != nil { 200 log.Error("Invalid pivot block number in database", "err", err) 201 return nil 202 } 203 return &pivot 204 } 205 206 // WriteLastPivotNumber stores the number of the last pivot block. 207 func WriteLastPivotNumber(db xcbdb.KeyValueWriter, pivot uint64) { 208 enc, err := rlp.EncodeToBytes(pivot) 209 if err != nil { 210 log.Crit("Failed to encode pivot block number", "err", err) 211 } 212 if err := db.Put(lastPivotKey, enc); err != nil { 213 log.Crit("Failed to store pivot block number", "err", err) 214 } 215 } 216 217 // ReadFastTrieProgress retrieves the number of tries nodes fast synced to allow 218 // reporting correct numbers across restarts. 219 func ReadFastTrieProgress(db xcbdb.KeyValueReader) uint64 { 220 data, _ := db.Get(fastTrieProgressKey) 221 if len(data) == 0 { 222 return 0 223 } 224 return new(big.Int).SetBytes(data).Uint64() 225 } 226 227 // WriteFastTrieProgress stores the fast sync trie process counter to support 228 // retrieving it across restarts. 229 func WriteFastTrieProgress(db xcbdb.KeyValueWriter, count uint64) { 230 if err := db.Put(fastTrieProgressKey, new(big.Int).SetUint64(count).Bytes()); err != nil { 231 log.Crit("Failed to store fast sync trie progress", "err", err) 232 } 233 } 234 235 // ReadTxIndexTail retrieves the number of oldest indexed block 236 // whose transaction indices has been indexed. If the corresponding entry 237 // is non-existent in database it means the indexing has been finished. 238 func ReadTxIndexTail(db xcbdb.KeyValueReader) *uint64 { 239 data, _ := db.Get(txIndexTailKey) 240 if len(data) != 8 { 241 return nil 242 } 243 number := binary.BigEndian.Uint64(data) 244 return &number 245 } 246 247 // WriteTxIndexTail stores the number of oldest indexed block 248 // into database. 249 func WriteTxIndexTail(db xcbdb.KeyValueWriter, number uint64) { 250 if err := db.Put(txIndexTailKey, encodeBlockNumber(number)); err != nil { 251 log.Crit("Failed to store the transaction index tail", "err", err) 252 } 253 } 254 255 // ReadFastTxLookupLimit retrieves the tx lookup limit used in fast sync. 256 func ReadFastTxLookupLimit(db xcbdb.KeyValueReader) *uint64 { 257 data, _ := db.Get(fastTxLookupLimitKey) 258 if len(data) != 8 { 259 return nil 260 } 261 number := binary.BigEndian.Uint64(data) 262 return &number 263 } 264 265 // WriteFastTxLookupLimit stores the txlookup limit used in fast sync into database. 266 func WriteFastTxLookupLimit(db xcbdb.KeyValueWriter, number uint64) { 267 if err := db.Put(fastTxLookupLimitKey, encodeBlockNumber(number)); err != nil { 268 log.Crit("Failed to store transaction lookup limit for fast sync", "err", err) 269 } 270 } 271 272 // ReadHeaderRLP retrieves a block header in its raw RLP database encoding. 273 func ReadHeaderRLP(db xcbdb.Reader, hash common.Hash, number uint64) rlp.RawValue { 274 // First try to look up the data in ancient database. Extra hash 275 // comparison is necessary since ancient database only maintains 276 // the canonical data. 277 data, _ := db.Ancient(freezerHeaderTable, number) 278 if len(data) > 0 && crypto.SHA3Hash(data) == hash { 279 return data 280 } 281 // Then try to look up the data in leveldb. 282 data, _ = db.Get(headerKey(number, hash)) 283 if len(data) > 0 { 284 return data 285 } 286 // In the background freezer is moving data from leveldb to flatten files. 287 // So during the first check for ancient db, the data is not yet in there, 288 // but when we reach into leveldb, the data was already moved. That would 289 // result in a not found error. 290 data, _ = db.Ancient(freezerHeaderTable, number) 291 if len(data) > 0 && crypto.SHA3Hash(data) == hash { 292 return data 293 } 294 return nil // Can't find the data anywhere. 295 } 296 297 // HasHeader verifies the existence of a block header corresponding to the hash. 298 func HasHeader(db xcbdb.Reader, hash common.Hash, number uint64) bool { 299 if has, err := db.Ancient(freezerHashTable, number); err == nil && common.BytesToHash(has) == hash { 300 return true 301 } 302 if has, err := db.Has(headerKey(number, hash)); !has || err != nil { 303 return false 304 } 305 return true 306 } 307 308 // ReadHeader retrieves the block header corresponding to the hash. 309 func ReadHeader(db xcbdb.Reader, hash common.Hash, number uint64) *types.Header { 310 data := ReadHeaderRLP(db, hash, number) 311 if len(data) == 0 { 312 return nil 313 } 314 header := new(types.Header) 315 if err := rlp.Decode(bytes.NewReader(data), header); err != nil { 316 log.Error("Invalid block header RLP", "hash", hash, "err", err) 317 return nil 318 } 319 return header 320 } 321 322 // WriteHeader stores a block header into the database and also stores the hash- 323 // to-number mapping. 324 func WriteHeader(db xcbdb.KeyValueWriter, header *types.Header) { 325 var ( 326 hash = header.Hash() 327 number = header.Number.Uint64() 328 ) 329 // Write the hash -> number mapping 330 WriteHeaderNumber(db, hash, number) 331 332 // Write the encoded header 333 data, err := rlp.EncodeToBytes(header) 334 if err != nil { 335 log.Crit("Failed to RLP encode header", "err", err) 336 } 337 key := headerKey(number, hash) 338 if err := db.Put(key, data); err != nil { 339 log.Crit("Failed to store header", "err", err) 340 } 341 } 342 343 // DeleteHeader removes all block header data associated with a hash. 344 func DeleteHeader(db xcbdb.KeyValueWriter, hash common.Hash, number uint64) { 345 deleteHeaderWithoutNumber(db, hash, number) 346 if err := db.Delete(headerNumberKey(hash)); err != nil { 347 log.Crit("Failed to delete hash to number mapping", "err", err) 348 } 349 } 350 351 // deleteHeaderWithoutNumber removes only the block header but does not remove 352 // the hash to number mapping. 353 func deleteHeaderWithoutNumber(db xcbdb.KeyValueWriter, hash common.Hash, number uint64) { 354 if err := db.Delete(headerKey(number, hash)); err != nil { 355 log.Crit("Failed to delete header", "err", err) 356 } 357 } 358 359 // ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. 360 func ReadBodyRLP(db xcbdb.Reader, hash common.Hash, number uint64) rlp.RawValue { 361 // First try to look up the data in ancient database. Extra hash 362 // comparison is necessary since ancient database only maintains 363 // the canonical data. 364 data, _ := db.Ancient(freezerBodiesTable, number) 365 if len(data) > 0 { 366 h, _ := db.Ancient(freezerHashTable, number) 367 if common.BytesToHash(h) == hash { 368 return data 369 } 370 } 371 // Then try to look up the data in leveldb. 372 data, _ = db.Get(blockBodyKey(number, hash)) 373 if len(data) > 0 { 374 return data 375 } 376 // In the background freezer is moving data from leveldb to flatten files. 377 // So during the first check for ancient db, the data is not yet in there, 378 // but when we reach into leveldb, the data was already moved. That would 379 // result in a not found error. 380 data, _ = db.Ancient(freezerBodiesTable, number) 381 if len(data) > 0 { 382 h, _ := db.Ancient(freezerHashTable, number) 383 if common.BytesToHash(h) == hash { 384 return data 385 } 386 } 387 return nil // Can't find the data anywhere. 388 } 389 390 // ReadCanonicalBodyRLP retrieves the block body (transactions and uncles) for the canonical 391 // block at number, in RLP encoding. 392 func ReadCanonicalBodyRLP(db xcbdb.Reader, number uint64) rlp.RawValue { 393 // If it's an ancient one, we don't need the canonical hash 394 data, _ := db.Ancient(freezerBodiesTable, number) 395 if len(data) == 0 { 396 // Need to get the hash 397 data, _ = db.Get(blockBodyKey(number, ReadCanonicalHash(db, number))) 398 // In the background freezer is moving data from leveldb to flatten files. 399 // So during the first check for ancient db, the data is not yet in there, 400 // but when we reach into leveldb, the data was already moved. That would 401 // result in a not found error. 402 if len(data) == 0 { 403 data, _ = db.Ancient(freezerBodiesTable, number) 404 } 405 } 406 return data 407 } 408 409 // WriteBodyRLP stores an RLP encoded block body into the database. 410 func WriteBodyRLP(db xcbdb.KeyValueWriter, hash common.Hash, number uint64, rlp rlp.RawValue) { 411 if err := db.Put(blockBodyKey(number, hash), rlp); err != nil { 412 log.Crit("Failed to store block body", "err", err) 413 } 414 } 415 416 // HasBody verifies the existence of a block body corresponding to the hash. 417 func HasBody(db xcbdb.Reader, hash common.Hash, number uint64) bool { 418 if has, err := db.Ancient(freezerHashTable, number); err == nil && common.BytesToHash(has) == hash { 419 return true 420 } 421 if has, err := db.Has(blockBodyKey(number, hash)); !has || err != nil { 422 return false 423 } 424 return true 425 } 426 427 // ReadBody retrieves the block body corresponding to the hash. 428 func ReadBody(db xcbdb.Reader, hash common.Hash, number uint64) *types.Body { 429 data := ReadBodyRLP(db, hash, number) 430 if len(data) == 0 { 431 return nil 432 } 433 body := new(types.Body) 434 if err := rlp.Decode(bytes.NewReader(data), body); err != nil { 435 log.Error("Invalid block body RLP", "hash", hash, "err", err) 436 return nil 437 } 438 return body 439 } 440 441 // WriteBody stores a block body into the database. 442 func WriteBody(db xcbdb.KeyValueWriter, hash common.Hash, number uint64, body *types.Body) { 443 data, err := rlp.EncodeToBytes(body) 444 if err != nil { 445 log.Crit("Failed to RLP encode body", "err", err) 446 } 447 WriteBodyRLP(db, hash, number, data) 448 } 449 450 // DeleteBody removes all block body data associated with a hash. 451 func DeleteBody(db xcbdb.KeyValueWriter, hash common.Hash, number uint64) { 452 if err := db.Delete(blockBodyKey(number, hash)); err != nil { 453 log.Crit("Failed to delete block body", "err", err) 454 } 455 } 456 457 // ReadTdRLP retrieves a block's total difficulty corresponding to the hash in RLP encoding. 458 func ReadTdRLP(db xcbdb.Reader, hash common.Hash, number uint64) rlp.RawValue { 459 // First try to look up the data in ancient database. Extra hash 460 // comparison is necessary since ancient database only maintains 461 // the canonical data. 462 data, _ := db.Ancient(freezerDifficultyTable, number) 463 if len(data) > 0 { 464 h, _ := db.Ancient(freezerHashTable, number) 465 if common.BytesToHash(h) == hash { 466 return data 467 } 468 } 469 // Then try to look up the data in leveldb. 470 data, _ = db.Get(headerTDKey(number, hash)) 471 if len(data) > 0 { 472 return data 473 } 474 // In the background freezer is moving data from leveldb to flatten files. 475 // So during the first check for ancient db, the data is not yet in there, 476 // but when we reach into leveldb, the data was already moved. That would 477 // result in a not found error. 478 data, _ = db.Ancient(freezerDifficultyTable, number) 479 if len(data) > 0 { 480 h, _ := db.Ancient(freezerHashTable, number) 481 if common.BytesToHash(h) == hash { 482 return data 483 } 484 } 485 return nil // Can't find the data anywhere. 486 } 487 488 // ReadTd retrieves a block's total difficulty corresponding to the hash. 489 func ReadTd(db xcbdb.Reader, hash common.Hash, number uint64) *big.Int { 490 data := ReadTdRLP(db, hash, number) 491 if len(data) == 0 { 492 return nil 493 } 494 td := new(big.Int) 495 if err := rlp.Decode(bytes.NewReader(data), td); err != nil { 496 log.Error("Invalid block total difficulty RLP", "hash", hash, "err", err) 497 return nil 498 } 499 return td 500 } 501 502 // WriteTd stores the total difficulty of a block into the database. 503 func WriteTd(db xcbdb.KeyValueWriter, hash common.Hash, number uint64, td *big.Int) { 504 data, err := rlp.EncodeToBytes(td) 505 if err != nil { 506 log.Crit("Failed to RLP encode block total difficulty", "err", err) 507 } 508 if err := db.Put(headerTDKey(number, hash), data); err != nil { 509 log.Crit("Failed to store block total difficulty", "err", err) 510 } 511 } 512 513 // DeleteTd removes all block total difficulty data associated with a hash. 514 func DeleteTd(db xcbdb.KeyValueWriter, hash common.Hash, number uint64) { 515 if err := db.Delete(headerTDKey(number, hash)); err != nil { 516 log.Crit("Failed to delete block total difficulty", "err", err) 517 } 518 } 519 520 // HasReceipts verifies the existence of all the transaction receipts belonging 521 // to a block. 522 func HasReceipts(db xcbdb.Reader, hash common.Hash, number uint64) bool { 523 if has, err := db.Ancient(freezerHashTable, number); err == nil && common.BytesToHash(has) == hash { 524 return true 525 } 526 if has, err := db.Has(blockReceiptsKey(number, hash)); !has || err != nil { 527 return false 528 } 529 return true 530 } 531 532 // ReadReceiptsRLP retrieves all the transaction receipts belonging to a block in RLP encoding. 533 func ReadReceiptsRLP(db xcbdb.Reader, hash common.Hash, number uint64) rlp.RawValue { 534 // First try to look up the data in ancient database. Extra hash 535 // comparison is necessary since ancient database only maintains 536 // the canonical data. 537 data, _ := db.Ancient(freezerReceiptTable, number) 538 if len(data) > 0 { 539 h, _ := db.Ancient(freezerHashTable, number) 540 if common.BytesToHash(h) == hash { 541 return data 542 } 543 } 544 // Then try to look up the data in leveldb. 545 data, _ = db.Get(blockReceiptsKey(number, hash)) 546 if len(data) > 0 { 547 return data 548 } 549 // In the background freezer is moving data from leveldb to flatten files. 550 // So during the first check for ancient db, the data is not yet in there, 551 // but when we reach into leveldb, the data was already moved. That would 552 // result in a not found error. 553 data, _ = db.Ancient(freezerReceiptTable, number) 554 if len(data) > 0 { 555 h, _ := db.Ancient(freezerHashTable, number) 556 if common.BytesToHash(h) == hash { 557 return data 558 } 559 } 560 return nil // Can't find the data anywhere. 561 } 562 563 // ReadRawReceipts retrieves all the transaction receipts belonging to a block. 564 // The receipt metadata fields are not guaranteed to be populated, so they 565 // should not be used. Use ReadReceipts instead if the metadata is needed. 566 func ReadRawReceipts(db xcbdb.Reader, hash common.Hash, number uint64) types.Receipts { 567 // Retrieve the flattened receipt slice 568 data := ReadReceiptsRLP(db, hash, number) 569 if len(data) == 0 { 570 return nil 571 } 572 // Convert the receipts from their storage form to their internal representation 573 storageReceipts := []*types.ReceiptForStorage{} 574 if err := rlp.DecodeBytes(data, &storageReceipts); err != nil { 575 log.Error("Invalid receipt array RLP", "hash", hash, "err", err) 576 return nil 577 } 578 receipts := make(types.Receipts, len(storageReceipts)) 579 for i, storageReceipt := range storageReceipts { 580 receipts[i] = (*types.Receipt)(storageReceipt) 581 } 582 return receipts 583 } 584 585 // ReadReceipts retrieves all the transaction receipts belonging to a block, including 586 // its correspoinding metadata fields. If it is unable to populate these metadata 587 // fields then nil is returned. 588 // 589 // The current implementation populates these metadata fields by reading the receipts' 590 // corresponding block body, so if the block body is not found it will return nil even 591 // if the receipt itself is stored. 592 func ReadReceipts(db xcbdb.Reader, hash common.Hash, number uint64, config *params.ChainConfig) types.Receipts { 593 // We're deriving many fields from the block body, retrieve beside the receipt 594 receipts := ReadRawReceipts(db, hash, number) 595 if receipts == nil { 596 return nil 597 } 598 body := ReadBody(db, hash, number) 599 if body == nil { 600 log.Error("Missing body but have receipt", "hash", hash, "number", number) 601 return nil 602 } 603 if err := receipts.DeriveFields(config, hash, number, body.Transactions); err != nil { 604 log.Error("Failed to derive block receipts fields", "hash", hash, "number", number, "err", err) 605 return nil 606 } 607 return receipts 608 } 609 610 // WriteReceipts stores all the transaction receipts belonging to a block. 611 func WriteReceipts(db xcbdb.KeyValueWriter, hash common.Hash, number uint64, receipts types.Receipts) { 612 // Convert the receipts into their storage form and serialize them 613 storageReceipts := make([]*types.ReceiptForStorage, len(receipts)) 614 for i, receipt := range receipts { 615 storageReceipts[i] = (*types.ReceiptForStorage)(receipt) 616 } 617 bytes, err := rlp.EncodeToBytes(storageReceipts) 618 if err != nil { 619 log.Crit("Failed to encode block receipts", "err", err) 620 } 621 // Store the flattened receipt slice 622 if err := db.Put(blockReceiptsKey(number, hash), bytes); err != nil { 623 log.Crit("Failed to store block receipts", "err", err) 624 } 625 } 626 627 // DeleteReceipts removes all receipt data associated with a block hash. 628 func DeleteReceipts(db xcbdb.KeyValueWriter, hash common.Hash, number uint64) { 629 if err := db.Delete(blockReceiptsKey(number, hash)); err != nil { 630 log.Crit("Failed to delete block receipts", "err", err) 631 } 632 } 633 634 // ReadBlock retrieves an entire block corresponding to the hash, assembling it 635 // back from the stored header and body. If either the header or body could not 636 // be retrieved nil is returned. 637 // 638 // Note, due to concurrent download of header and block body the header and thus 639 // canonical hash can be stored in the database but the body data not (yet). 640 func ReadBlock(db xcbdb.Reader, hash common.Hash, number uint64) *types.Block { 641 header := ReadHeader(db, hash, number) 642 if header == nil { 643 return nil 644 } 645 body := ReadBody(db, hash, number) 646 if body == nil { 647 return nil 648 } 649 return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles) 650 } 651 652 // WriteBlock serializes a block into the database, header and body separately. 653 func WriteBlock(db xcbdb.KeyValueWriter, block *types.Block) { 654 WriteBody(db, block.Hash(), block.NumberU64(), block.Body()) 655 WriteHeader(db, block.Header()) 656 } 657 658 // WriteAncientBlock writes entire block data into ancient store and returns the total written size. 659 func WriteAncientBlock(db xcbdb.AncientWriter, block *types.Block, receipts types.Receipts, td *big.Int) int { 660 // Encode all block components to RLP format. 661 headerBlob, err := rlp.EncodeToBytes(block.Header()) 662 if err != nil { 663 log.Crit("Failed to RLP encode block header", "err", err) 664 } 665 bodyBlob, err := rlp.EncodeToBytes(block.Body()) 666 if err != nil { 667 log.Crit("Failed to RLP encode body", "err", err) 668 } 669 storageReceipts := make([]*types.ReceiptForStorage, len(receipts)) 670 for i, receipt := range receipts { 671 storageReceipts[i] = (*types.ReceiptForStorage)(receipt) 672 } 673 receiptBlob, err := rlp.EncodeToBytes(storageReceipts) 674 if err != nil { 675 log.Crit("Failed to RLP encode block receipts", "err", err) 676 } 677 tdBlob, err := rlp.EncodeToBytes(td) 678 if err != nil { 679 log.Crit("Failed to RLP encode block total difficulty", "err", err) 680 } 681 // Write all blob to flatten files. 682 err = db.AppendAncient(block.NumberU64(), block.Hash().Bytes(), headerBlob, bodyBlob, receiptBlob, tdBlob) 683 if err != nil { 684 log.Crit("Failed to write block data to ancient store", "err", err) 685 } 686 return len(headerBlob) + len(bodyBlob) + len(receiptBlob) + len(tdBlob) + common.HashLength 687 } 688 689 // DeleteBlock removes all block data associated with a hash. 690 func DeleteBlock(db xcbdb.KeyValueWriter, hash common.Hash, number uint64) { 691 DeleteReceipts(db, hash, number) 692 DeleteHeader(db, hash, number) 693 DeleteBody(db, hash, number) 694 DeleteTd(db, hash, number) 695 } 696 697 // DeleteBlockWithoutNumber removes all block data associated with a hash, except 698 // the hash to number mapping. 699 func DeleteBlockWithoutNumber(db xcbdb.KeyValueWriter, hash common.Hash, number uint64) { 700 DeleteReceipts(db, hash, number) 701 deleteHeaderWithoutNumber(db, hash, number) 702 DeleteBody(db, hash, number) 703 DeleteTd(db, hash, number) 704 } 705 706 // FindCommonAncestor returns the last common ancestor of two block headers 707 func FindCommonAncestor(db xcbdb.Reader, a, b *types.Header) *types.Header { 708 for bn := b.Number.Uint64(); a.Number.Uint64() > bn; { 709 a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1) 710 if a == nil { 711 return nil 712 } 713 } 714 for an := a.Number.Uint64(); an < b.Number.Uint64(); { 715 b = ReadHeader(db, b.ParentHash, b.Number.Uint64()-1) 716 if b == nil { 717 return nil 718 } 719 } 720 for a.Hash() != b.Hash() { 721 a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1) 722 if a == nil { 723 return nil 724 } 725 b = ReadHeader(db, b.ParentHash, b.Number.Uint64()-1) 726 if b == nil { 727 return nil 728 } 729 } 730 return a 731 }