You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

105 lines
2.4 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package blocks
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "encoding/json"
  6. "github.com/syndtr/goleveldb/leveldb"
  7. "github.com/syndtr/goleveldb/leveldb/opt"
  8. . "github.com/tendermint/tendermint/binary"
  9. . "github.com/tendermint/tendermint/common"
  10. )
  11. var (
  12. blockStoreKey = []byte("blockStore")
  13. )
  14. //-----------------------------------------------------------------------------
  15. type BlockStoreJSON struct {
  16. Height uint32
  17. }
  18. func (bsj BlockStoreJSON) Save(db *leveldb.DB) {
  19. bytes, err := json.Marshal(bsj)
  20. if err != nil {
  21. Panicf("Could not marshal state bytes: %v", err)
  22. }
  23. db.Put(blockStoreKey, bytes, nil)
  24. }
  25. func LoadBlockStoreJSON(db *leveldb.DB) BlockStoreJSON {
  26. bytes, err := db.Get(blockStoreKey, nil)
  27. if err != nil {
  28. Panicf("Could not load BlockStoreJSON from db: %v", err)
  29. }
  30. if bytes == nil {
  31. return BlockStoreJSON{
  32. Height: 0,
  33. }
  34. }
  35. bsj := BlockStoreJSON{}
  36. err = json.Unmarshal(bytes, &bsj)
  37. if err != nil {
  38. Panicf("Could not unmarshal bytes: %X", bytes)
  39. }
  40. return bsj
  41. }
  42. //-----------------------------------------------------------------------------
  43. /*
  44. Simple low level store for blocks, which is actually stored as separte parts (wire format).
  45. */
  46. type BlockStore struct {
  47. height uint32
  48. db *leveldb.DB
  49. }
  50. func NewBlockStore(db *leveldb.DB) *BlockStore {
  51. bsjson := LoadBlockStoreJSON(db)
  52. return &BlockStore{
  53. height: bsjson.Height,
  54. db: db,
  55. }
  56. }
  57. // Height() returns the last known contiguous block height.
  58. func (bs *BlockStore) Height() uint32 {
  59. return bs.height
  60. }
  61. func (bs *BlockStore) LoadBlock(height uint32) *Block {
  62. blockBytes, err := bs.db.Get(calcBlockKey(height), nil)
  63. if err != nil {
  64. Panicf("Could not load block: %v", err)
  65. }
  66. if blockBytes == nil {
  67. return nil
  68. }
  69. var n int64
  70. return ReadBlock(bytes.NewReader(blockBytes), &n, &err)
  71. }
  72. // Writes are synchronous and atomic.
  73. func (bs *BlockStore) SaveBlock(block *Block) error {
  74. height := block.Height
  75. if height != bs.height+1 {
  76. return Errorf("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.height+1, height)
  77. }
  78. // Save block
  79. blockBytes := BinaryBytes(block)
  80. err := bs.db.Put(calcBlockKey(height), blockBytes, &opt.WriteOptions{Sync: true})
  81. // Save new BlockStoreJSON descriptor
  82. BlockStoreJSON{Height: height}.Save(bs.db)
  83. return err
  84. }
  85. //-----------------------------------------------------------------------------
  86. func calcBlockKey(height uint32) []byte {
  87. buf := [9]byte{'B'}
  88. binary.BigEndian.PutUint32(buf[1:9], height)
  89. return buf[:]
  90. }