github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/core/database_util.go (about) 1 // Copyright 2015 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 core 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 "github.com/ethereumproject/go-ethereum/common" 24 "github.com/ethereumproject/go-ethereum/core/types" 25 "github.com/ethereumproject/go-ethereum/ethdb" 26 "github.com/ethereumproject/go-ethereum/logger" 27 "github.com/ethereumproject/go-ethereum/logger/glog" 28 "github.com/ethereumproject/go-ethereum/rlp" 29 "math/big" 30 ) 31 32 var ( 33 headHeaderKey = []byte("LastHeader") 34 headBlockKey = []byte("LastBlock") 35 headFastKey = []byte("LastFast") 36 37 blockPrefix = []byte("block-") 38 blockNumPrefix = []byte("block-num-") 39 40 headerSuffix = []byte("-header") 41 bodySuffix = []byte("-body") 42 tdSuffix = []byte("-td") 43 44 txMetaSuffix = []byte{0x01} 45 receiptsPrefix = []byte("receipts-") 46 blockReceiptsPrefix = []byte("receipts-block-") 47 48 mipmapPre = []byte("mipmap-log-bloom-") 49 MIPMapLevels = []uint64{1000000, 500000, 100000, 50000, 1000} 50 51 blockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually] 52 53 preimagePrefix = "secure-key-" // preimagePrefix + hash -> preimage 54 lookupPrefix = []byte("l") // lookupPrefix + hash -> transaction/receipt lookup metadata 55 ) 56 57 // TxLookupEntry is a positional metadata to help looking up the data content of 58 // a transaction or receipt given only its hash. 59 type TxLookupEntry struct { 60 BlockHash common.Hash 61 BlockIndex uint64 62 Index uint64 63 } 64 65 // GetCanonicalHash retrieves a hash assigned to a canonical block number. 66 func GetCanonicalHash(db ethdb.Database, number uint64) common.Hash { 67 data, _ := db.Get(append(blockNumPrefix, big.NewInt(int64(number)).Bytes()...)) 68 if len(data) == 0 { 69 return common.Hash{} 70 } 71 return common.BytesToHash(data) 72 } 73 74 // GetHeadHeaderHash retrieves the hash of the current canonical head block's 75 // header. The difference between this and GetHeadBlockHash is that whereas the 76 // last block hash is only updated upon a full block import, the last header 77 // hash is updated already at header import, allowing head tracking for the 78 // light synchronization mechanism. 79 func GetHeadHeaderHash(db ethdb.Database) common.Hash { 80 data, _ := db.Get(headHeaderKey) 81 if len(data) == 0 { 82 return common.Hash{} 83 } 84 return common.BytesToHash(data) 85 } 86 87 // GetHeadBlockHash retrieves the hash of the current canonical head block. 88 func GetHeadBlockHash(db ethdb.Database) common.Hash { 89 data, _ := db.Get(headBlockKey) 90 if len(data) == 0 { 91 return common.Hash{} 92 } 93 return common.BytesToHash(data) 94 } 95 96 // GetHeadFastBlockHash retrieves the hash of the current canonical head block during 97 // fast synchronization. The difference between this and GetHeadBlockHash is that 98 // whereas the last block hash is only updated upon a full block import, the last 99 // fast hash is updated when importing pre-processed blocks. 100 func GetHeadFastBlockHash(db ethdb.Database) common.Hash { 101 data, _ := db.Get(headFastKey) 102 if len(data) == 0 { 103 return common.Hash{} 104 } 105 return common.BytesToHash(data) 106 } 107 108 // GetHeaderRLP retrieves a block header in its raw RLP database encoding, or nil 109 // if the header's not found. 110 func GetHeaderRLP(db ethdb.Database, hash common.Hash) rlp.RawValue { 111 data, _ := db.Get(append(append(blockPrefix, hash[:]...), headerSuffix...)) 112 return data 113 } 114 115 // GetHeader retrieves the block header corresponding to the hash, nil if none 116 // found. 117 func GetHeader(db ethdb.Database, hash common.Hash) *types.Header { 118 data := GetHeaderRLP(db, hash) 119 if len(data) == 0 { 120 return nil 121 } 122 header := new(types.Header) 123 if err := rlp.Decode(bytes.NewReader(data), header); err != nil { 124 glog.V(logger.Error).Infof("invalid block header RLP for hash %x: %v", hash, err) 125 return nil 126 } 127 return header 128 } 129 130 // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. 131 func GetBodyRLP(db ethdb.Database, hash common.Hash) rlp.RawValue { 132 data, _ := db.Get(append(append(blockPrefix, hash[:]...), bodySuffix...)) 133 return data 134 } 135 136 // GetBody retrieves the block body (transactons, uncles) corresponding to the 137 // hash, nil if none found. 138 func GetBody(db ethdb.Database, hash common.Hash) *types.Body { 139 data := GetBodyRLP(db, hash) 140 if len(data) == 0 { 141 return nil 142 } 143 body := new(types.Body) 144 if err := rlp.Decode(bytes.NewReader(data), body); err != nil { 145 glog.V(logger.Error).Infof("invalid block body RLP for hash %x: %v", hash, err) 146 return nil 147 } 148 return body 149 } 150 151 // GetTd retrieves a block's total difficulty corresponding to the hash, nil if 152 // none found. 153 func GetTd(db ethdb.Database, hash common.Hash) *big.Int { 154 data, _ := db.Get(append(append(blockPrefix, hash.Bytes()...), tdSuffix...)) 155 if len(data) == 0 { 156 return nil 157 } 158 td := new(big.Int) 159 if err := rlp.Decode(bytes.NewReader(data), td); err != nil { 160 glog.V(logger.Error).Infof("invalid block total difficulty RLP for hash %x: %v", hash, err) 161 return nil 162 } 163 return td 164 } 165 166 // GetBlock retrieves an entire block corresponding to the hash, assembling it 167 // back from the stored header and body. If either the header or body could not 168 // be retrieved nil is returned. 169 // 170 // Note, due to concurrent download of header and block body the header and thus 171 // canonical hash can be stored in the database but the body data not (yet). 172 func GetBlock(db ethdb.Database, hash common.Hash) *types.Block { 173 // Retrieve the block header and body contents 174 header := GetHeader(db, hash) 175 if header == nil { 176 return nil 177 } 178 body := GetBody(db, hash) 179 if body == nil { 180 return nil 181 } 182 // Reassemble the block and return 183 return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles) 184 } 185 186 // GetBlockReceipts retrieves the receipts generated by the transactions included 187 // in a block given by its hash. 188 func GetBlockReceipts(db ethdb.Database, hash common.Hash) types.Receipts { 189 data, _ := db.Get(append(blockReceiptsPrefix, hash[:]...)) 190 if len(data) == 0 { 191 return nil 192 } 193 storageReceipts := []*types.ReceiptForStorage{} 194 if err := rlp.DecodeBytes(data, &storageReceipts); err != nil { 195 glog.V(logger.Error).Infof("invalid receipt array RLP for hash %x: %v", hash, err) 196 return nil 197 } 198 receipts := make(types.Receipts, len(storageReceipts)) 199 for i, receipt := range storageReceipts { 200 receipts[i] = (*types.Receipt)(receipt) 201 } 202 return receipts 203 } 204 205 // GetTransaction retrieves a specific transaction from the database, along with 206 // its added positional metadata. 207 func GetTransaction(db ethdb.Database, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) { 208 // Retrieve the transaction itself from the database 209 data, _ := db.Get(hash.Bytes()) 210 if len(data) == 0 { 211 return nil, common.Hash{}, 0, 0 212 } 213 var tx types.Transaction 214 if err := rlp.DecodeBytes(data, &tx); err != nil { 215 return nil, common.Hash{}, 0, 0 216 } 217 // Retrieve the blockchain positional metadata 218 data, _ = db.Get(append(hash.Bytes(), txMetaSuffix...)) 219 if len(data) == 0 { 220 return nil, common.Hash{}, 0, 0 221 } 222 var meta struct { 223 BlockHash common.Hash 224 BlockIndex uint64 225 Index uint64 226 } 227 if err := rlp.DecodeBytes(data, &meta); err != nil { 228 return nil, common.Hash{}, 0, 0 229 } 230 return &tx, meta.BlockHash, meta.BlockIndex, meta.Index 231 } 232 233 // GetReceipt returns a receipt by hash 234 func GetReceipt(db ethdb.Database, txHash common.Hash) *types.Receipt { 235 data, _ := db.Get(append(receiptsPrefix, txHash[:]...)) 236 if len(data) == 0 { 237 return nil 238 } 239 var receipt types.ReceiptForStorage 240 err := rlp.DecodeBytes(data, &receipt) 241 if err != nil { 242 glog.V(logger.Core).Errorln("GetReceipt err:", err) 243 } 244 return (*types.Receipt)(&receipt) 245 } 246 247 // WriteCanonicalHash stores the canonical hash for the given block number. 248 func WriteCanonicalHash(db ethdb.Database, hash common.Hash, number uint64) error { 249 key := append(blockNumPrefix, big.NewInt(int64(number)).Bytes()...) 250 if err := db.Put(key, hash.Bytes()); err != nil { 251 glog.Fatalf("failed to store number to hash mapping into database: %v", err) 252 return err 253 } 254 return nil 255 } 256 257 // WriteHeadHeaderHash stores the head header's hash. 258 func WriteHeadHeaderHash(db ethdb.Database, hash common.Hash) error { 259 if err := db.Put(headHeaderKey, hash.Bytes()); err != nil { 260 glog.Fatalf("failed to store last header's hash into database: %v", err) 261 return err 262 } 263 return nil 264 } 265 266 // WriteHeadBlockHash stores the head block's hash. 267 func WriteHeadBlockHash(db ethdb.Database, hash common.Hash) error { 268 if err := db.Put(headBlockKey, hash.Bytes()); err != nil { 269 glog.Fatalf("failed to store last block's hash into database: %v", err) 270 return err 271 } 272 return nil 273 } 274 275 // WriteHeadFastBlockHash stores the fast head block's hash. 276 func WriteHeadFastBlockHash(db ethdb.Database, hash common.Hash) error { 277 if err := db.Put(headFastKey, hash.Bytes()); err != nil { 278 glog.Fatalf("failed to store last fast block's hash into database: %v", err) 279 return err 280 } 281 return nil 282 } 283 284 // WriteHeader serializes a block header into the database. 285 func WriteHeader(db ethdb.Database, header *types.Header) error { 286 data, err := rlp.EncodeToBytes(header) 287 if err != nil { 288 return err 289 } 290 key := append(append(blockPrefix, header.Hash().Bytes()...), headerSuffix...) 291 if err := db.Put(key, data); err != nil { 292 glog.Fatalf("failed to store header into database: %v", err) 293 return err 294 } 295 glog.V(logger.Detail).Infof("stored header #%v [%x…]", header.Number, header.Hash().Bytes()[:4]) 296 return nil 297 } 298 299 // WriteBody serializes the body of a block into the database. 300 func WriteBody(db ethdb.Database, hash common.Hash, body *types.Body) error { 301 data, err := rlp.EncodeToBytes(body) 302 if err != nil { 303 return err 304 } 305 key := append(append(blockPrefix, hash.Bytes()...), bodySuffix...) 306 if err := db.Put(key, data); err != nil { 307 glog.Fatalf("failed to store block body into database: %v", err) 308 return err 309 } 310 glog.V(logger.Detail).Infof("stored block body [%x…]", hash.Bytes()[:4]) 311 return nil 312 } 313 314 // WriteTd serializes the total difficulty of a block into the database. 315 func WriteTd(db ethdb.Database, hash common.Hash, td *big.Int) error { 316 data, err := rlp.EncodeToBytes(td) 317 if err != nil { 318 return err 319 } 320 key := append(append(blockPrefix, hash.Bytes()...), tdSuffix...) 321 if err := db.Put(key, data); err != nil { 322 glog.Fatalf("failed to store block total difficulty into database: %v", err) 323 return err 324 } 325 glog.V(logger.Detail).Infof("stored block total difficulty [%x…]: %v", hash.Bytes()[:4], td) 326 return nil 327 } 328 329 // WriteBlock serializes a block into the database, header and body separately. 330 func WriteBlock(db ethdb.Database, block *types.Block) error { 331 // Store the body first to retain database consistency 332 if err := WriteBody(db, block.Hash(), block.Body()); err != nil { 333 return err 334 } 335 336 // Store the header too, signaling full block ownership 337 if err := WriteHeader(db, block.Header()); err != nil { 338 return err 339 } 340 return nil 341 } 342 343 // WriteBlockReceipts stores all the transaction receipts belonging to a block 344 // as a single receipt slice. This is used during chain reorganisations for 345 // rescheduling dropped transactions. 346 func WriteBlockReceipts(db ethdb.Database, hash common.Hash, receipts types.Receipts) error { 347 // Convert the receipts into their storage form and serialize them 348 storageReceipts := make([]*types.ReceiptForStorage, len(receipts)) 349 for i, receipt := range receipts { 350 storageReceipts[i] = (*types.ReceiptForStorage)(receipt) 351 } 352 bytes, err := rlp.EncodeToBytes(storageReceipts) 353 if err != nil { 354 return err 355 } 356 // Store the flattened receipt slice 357 if err := db.Put(append(blockReceiptsPrefix, hash.Bytes()...), bytes); err != nil { 358 glog.Fatalf("failed to store block receipts into database: %v", err) 359 return err 360 } 361 glog.V(logger.Detail).Infof("stored block receipts [%x…]", hash.Bytes()[:4]) 362 return nil 363 } 364 365 // WriteTransactions stores the transactions associated with a specific block 366 // into the given database. Beside writing the transaction, the function also 367 // stores a metadata entry along with the transaction, detailing the position 368 // of this within the blockchain. 369 func WriteTransactions(db ethdb.Database, block *types.Block) error { 370 batch := db.NewBatch() 371 372 // Iterate over each transaction and encode it with its metadata 373 for i, tx := range block.Transactions() { 374 // Encode and queue up the transaction for storage 375 data, err := rlp.EncodeToBytes(tx) 376 if err != nil { 377 return err 378 } 379 if err := batch.Put(tx.Hash().Bytes(), data); err != nil { 380 return err 381 } 382 // Encode and queue up the transaction metadata for storage 383 meta := struct { 384 BlockHash common.Hash 385 BlockIndex uint64 386 Index uint64 387 }{ 388 BlockHash: block.Hash(), 389 BlockIndex: block.NumberU64(), 390 Index: uint64(i), 391 } 392 data, err = rlp.EncodeToBytes(meta) 393 if err != nil { 394 return err 395 } 396 if err := batch.Put(append(tx.Hash().Bytes(), txMetaSuffix...), data); err != nil { 397 return err 398 } 399 } 400 // Write the scheduled data into the database 401 if err := batch.Write(); err != nil { 402 glog.Fatalf("failed to store transactions into database: %v", err) 403 return err 404 } 405 return nil 406 } 407 408 // WriteReceipts stores a batch of transaction receipts into the database. 409 func WriteReceipts(db ethdb.Database, receipts types.Receipts) error { 410 batch := db.NewBatch() 411 412 // Iterate over all the receipts and queue them for database injection 413 for _, receipt := range receipts { 414 storageReceipt := (*types.ReceiptForStorage)(receipt) 415 data, err := rlp.EncodeToBytes(storageReceipt) 416 if err != nil { 417 return err 418 } 419 if err := batch.Put(append(receiptsPrefix, receipt.TxHash.Bytes()...), data); err != nil { 420 return err 421 } 422 } 423 // Write the scheduled data into the database 424 if err := batch.Write(); err != nil { 425 glog.Fatalf("failed to store receipts into database: %v", err) 426 return err 427 } 428 return nil 429 } 430 431 // DeleteCanonicalHash removes the number to hash canonical mapping. 432 func DeleteCanonicalHash(db ethdb.Database, number uint64) { 433 db.Delete(append(blockNumPrefix, big.NewInt(int64(number)).Bytes()...)) 434 } 435 436 // DeleteHeader removes all block header data associated with a hash. 437 func DeleteHeader(db ethdb.Database, hash common.Hash) { 438 db.Delete(append(append(blockPrefix, hash.Bytes()...), headerSuffix...)) 439 } 440 441 // DeleteBody removes all block body data associated with a hash. 442 func DeleteBody(db ethdb.Database, hash common.Hash) { 443 db.Delete(append(append(blockPrefix, hash.Bytes()...), bodySuffix...)) 444 } 445 446 // DeleteTd removes all block total difficulty data associated with a hash. 447 func DeleteTd(db ethdb.Database, hash common.Hash) { 448 db.Delete(append(append(blockPrefix, hash.Bytes()...), tdSuffix...)) 449 } 450 451 // DeleteBlock removes all block data associated with a hash. 452 func DeleteBlock(db ethdb.Database, hash common.Hash) { 453 DeleteBlockReceipts(db, hash) 454 DeleteHeader(db, hash) 455 DeleteBody(db, hash) 456 DeleteTd(db, hash) 457 } 458 459 // DeleteBlockReceipts removes all receipt data associated with a block hash. 460 func DeleteBlockReceipts(db ethdb.Database, hash common.Hash) { 461 db.Delete(append(blockReceiptsPrefix, hash.Bytes()...)) 462 } 463 464 // DeleteTransaction removes all transaction data associated with a hash. 465 func DeleteTransaction(db ethdb.Database, hash common.Hash) { 466 db.Delete(hash.Bytes()) 467 db.Delete(append(hash.Bytes(), txMetaSuffix...)) 468 } 469 470 // DeleteReceipt removes all receipt data associated with a transaction hash. 471 func DeleteReceipt(db ethdb.Database, hash common.Hash) { 472 db.Delete(append(receiptsPrefix, hash.Bytes()...)) 473 } 474 475 // PreimageTable returns a Database instance with the key prefix for preimage entries. 476 func PreimageTable(db ethdb.Database) ethdb.Database { 477 return ethdb.NewTable(db, preimagePrefix) 478 } 479 480 // WritePreimages writes the provided set of preimages to the database. `number` is the 481 // current block number, and is used for debug messages only. 482 func WritePreimages(db ethdb.Database, number uint64, preimages map[common.Hash][]byte) error { 483 table := PreimageTable(db) 484 batch := table.NewBatch() 485 hitCount := 0 486 for hash, preimage := range preimages { 487 if _, err := table.Get(hash.Bytes()); err != nil { 488 batch.Put(hash.Bytes(), preimage) 489 hitCount++ 490 } 491 } 492 //preimageCounter.Inc(int64(len(preimages))) 493 //preimageHitCounter.Inc(int64(hitCount)) 494 if hitCount > 0 { 495 if err := batch.Write(); err != nil { 496 return fmt.Errorf("preimage write fail for block %d: %v", number, err) 497 } 498 } 499 return nil 500 } 501 502 // WriteTxLookupEntries stores a positional metadata for every transaction from 503 // a block, enabling hash based transaction and receipt lookups. 504 func WriteTxLookupEntries(db ethdb.Putter, block *types.Block) error { 505 // Iterate over each transaction and encode its metadata 506 for i, tx := range block.Transactions() { 507 entry := TxLookupEntry{ 508 BlockHash: block.Hash(), 509 BlockIndex: block.NumberU64(), 510 Index: uint64(i), 511 } 512 data, err := rlp.EncodeToBytes(entry) 513 if err != nil { 514 return err 515 } 516 if err := db.Put(append(lookupPrefix, tx.Hash().Bytes()...), data); err != nil { 517 return err 518 } 519 } 520 return nil 521 } 522 523 // [deprecated by the header/block split, remove eventually] 524 // GetBlockByHashOld returns the old combined block corresponding to the hash 525 // or nil if not found. This method is only used by the upgrade mechanism to 526 // access the old combined block representation. It will be dropped after the 527 // network transitions to eth/63. 528 func GetBlockByHashOld(db ethdb.Database, hash common.Hash) *types.Block { 529 data, _ := db.Get(append(blockHashPrefix, hash[:]...)) 530 if len(data) == 0 { 531 return nil 532 } 533 var block types.StorageBlock 534 if err := rlp.Decode(bytes.NewReader(data), &block); err != nil { 535 glog.V(logger.Error).Infof("invalid block RLP for hash %x: %v", hash, err) 536 return nil 537 } 538 return (*types.Block)(&block) 539 } 540 541 // returns a formatted MIP mapped key by adding prefix, canonical number and level 542 // 543 // ex. fn(98, 1000) = (prefix || 1000 || 0) 544 func mipmapKey(num, level uint64) []byte { 545 lkey := make([]byte, 8) 546 binary.BigEndian.PutUint64(lkey, level) 547 key := new(big.Int).SetUint64(num / level * level) 548 549 return append(mipmapPre, append(lkey, key.Bytes()...)...) 550 } 551 552 // WriteMapmapBloom writes each address included in the receipts' logs to the 553 // MIP bloom bin. 554 func WriteMipmapBloom(db ethdb.Database, number uint64, receipts types.Receipts) error { 555 batch := db.NewBatch() 556 for _, level := range MIPMapLevels { 557 key := mipmapKey(number, level) 558 bloomDat, _ := db.Get(key) 559 bloom := types.BytesToBloom(bloomDat) 560 for _, receipt := range receipts { 561 for _, log := range receipt.Logs { 562 bloom.Add(log.Address.Big()) 563 } 564 } 565 batch.Put(key, bloom.Bytes()) 566 } 567 if err := batch.Write(); err != nil { 568 return fmt.Errorf("mipmap write fail for: %d: %v", number, err) 569 } 570 return nil 571 } 572 573 // GetMipmapBloom returns a bloom filter using the number and level as input 574 // parameters. For available levels see MIPMapLevels. 575 func GetMipmapBloom(db ethdb.Database, number, level uint64) types.Bloom { 576 bloomDat, _ := db.Get(mipmapKey(number, level)) 577 return types.BytesToBloom(bloomDat) 578 } 579 580 // GetBlockChainVersion reads the version number from db. 581 func GetBlockChainVersion(db ethdb.Database) int { 582 var vsn uint 583 enc, _ := db.Get([]byte("BlockchainVersion")) 584 rlp.DecodeBytes(enc, &vsn) 585 return int(vsn) 586 } 587 588 // WriteBlockChainVersion writes vsn as the version number to db. 589 func WriteBlockChainVersion(db ethdb.Database, vsn int) { 590 enc, _ := rlp.EncodeToBytes(uint(vsn)) 591 db.Put([]byte("BlockchainVersion"), enc) 592 }