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.

185 lines
4.6 KiB

10 years ago
  1. package blocks
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "encoding/json"
  6. "io"
  7. . "github.com/tendermint/tendermint/binary"
  8. . "github.com/tendermint/tendermint/common"
  9. db_ "github.com/tendermint/tendermint/db"
  10. )
  11. //-----------------------------------------------------------------------------
  12. /*
  13. Simple low level store for blocks, which is actually stored as separte parts (wire format).
  14. */
  15. type BlockStore struct {
  16. height uint32
  17. db db_.DB
  18. }
  19. func NewBlockStore(db db_.DB) *BlockStore {
  20. bsjson := LoadBlockStoreJSON(db)
  21. return &BlockStore{
  22. height: bsjson.Height,
  23. db: db,
  24. }
  25. }
  26. // Height() returns the last known contiguous block height.
  27. func (bs *BlockStore) Height() uint32 {
  28. return bs.height
  29. }
  30. func (bs *BlockStore) GetReader(key []byte) io.Reader {
  31. bytez := bs.db.Get(key)
  32. if bytez == nil {
  33. return nil
  34. }
  35. return bytes.NewReader(bytez)
  36. }
  37. func (bs *BlockStore) LoadBlock(height uint32) *Block {
  38. var n int64
  39. var err error
  40. meta := ReadBlockMeta(bs.GetReader(calcBlockMetaKey(height)), &n, &err)
  41. if err != nil {
  42. Panicf("Error reading block meta: %v", err)
  43. }
  44. bytez := []byte{}
  45. for i := uint16(0); i < meta.Parts.Total; i++ {
  46. part := bs.LoadBlockPart(height, i)
  47. bytez = append(bytez, part.Bytes...)
  48. }
  49. block := ReadBlock(bytes.NewReader(bytez), &n, &err)
  50. if err != nil {
  51. Panicf("Error reading block: %v", err)
  52. }
  53. return block
  54. }
  55. func (bs *BlockStore) LoadBlockPart(height uint32, index uint16) *Part {
  56. var n int64
  57. var err error
  58. part := ReadPart(bs.GetReader(calcBlockPartKey(height, index)), &n, &err)
  59. if err != nil {
  60. Panicf("Error reading block part: %v", err)
  61. }
  62. return part
  63. }
  64. func (bs *BlockStore) LoadBlockValidation(height uint32) *Validation {
  65. var n int64
  66. var err error
  67. validation := ReadValidation(bs.GetReader(calcBlockValidationKey(height)), &n, &err)
  68. if err != nil {
  69. Panicf("Error reading validation: %v", err)
  70. }
  71. return &validation
  72. }
  73. func (bs *BlockStore) SaveBlock(block *Block, blockParts *PartSet) {
  74. height := block.Height
  75. if height != bs.height+1 {
  76. Panicf("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.height+1, height)
  77. }
  78. if !blockParts.IsComplete() {
  79. Panicf("BlockStore can only save complete block part sets")
  80. }
  81. meta := BlockMeta{Hash: block.Hash(), Parts: blockParts.Header()}
  82. // Save block meta
  83. metaBytes := BinaryBytes(meta)
  84. bs.db.Set(calcBlockMetaKey(height), metaBytes)
  85. // Save block parts
  86. for i := uint16(0); i < blockParts.Total(); i++ {
  87. bs.saveBlockPart(height, i, blockParts.GetPart(i))
  88. }
  89. // Save block validation (duplicate and separate)
  90. validationBytes := BinaryBytes(&block.Validation)
  91. bs.db.Set(calcBlockValidationKey(height), validationBytes)
  92. // Save new BlockStoreJSON descriptor
  93. BlockStoreJSON{Height: height}.Save(bs.db)
  94. }
  95. func (bs *BlockStore) saveBlockPart(height uint32, index uint16, part *Part) {
  96. if height != bs.height+1 {
  97. Panicf("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.height+1, height)
  98. }
  99. partBytes := BinaryBytes(part)
  100. bs.db.Set(calcBlockPartKey(height, index), partBytes)
  101. }
  102. //-----------------------------------------------------------------------------
  103. type BlockMeta struct {
  104. Hash []byte
  105. Parts PartSetHeader
  106. }
  107. func ReadBlockMeta(r io.Reader, n *int64, err *error) BlockMeta {
  108. return BlockMeta{
  109. Hash: ReadByteSlice(r, n, err),
  110. Parts: ReadPartSetHeader(r, n, err),
  111. }
  112. }
  113. func (bm BlockMeta) WriteTo(w io.Writer) (n int64, err error) {
  114. WriteByteSlice(w, bm.Hash, &n, &err)
  115. WriteBinary(w, bm.Parts, &n, &err)
  116. return
  117. }
  118. //-----------------------------------------------------------------------------
  119. func calcBlockMetaKey(height uint32) []byte {
  120. buf := [5]byte{'H'}
  121. binary.BigEndian.PutUint32(buf[1:5], height)
  122. return buf[:]
  123. }
  124. func calcBlockPartKey(height uint32, partIndex uint16) []byte {
  125. buf := [7]byte{'P'}
  126. binary.BigEndian.PutUint32(buf[1:5], height)
  127. binary.BigEndian.PutUint16(buf[5:7], partIndex)
  128. return buf[:]
  129. }
  130. func calcBlockValidationKey(height uint32) []byte {
  131. buf := [5]byte{'V'}
  132. binary.BigEndian.PutUint32(buf[1:5], height)
  133. return buf[:]
  134. }
  135. //-----------------------------------------------------------------------------
  136. var blockStoreKey = []byte("blockStore")
  137. type BlockStoreJSON struct {
  138. Height uint32
  139. }
  140. func (bsj BlockStoreJSON) Save(db db_.DB) {
  141. bytes, err := json.Marshal(bsj)
  142. if err != nil {
  143. Panicf("Could not marshal state bytes: %v", err)
  144. }
  145. db.Set(blockStoreKey, bytes)
  146. }
  147. func LoadBlockStoreJSON(db db_.DB) BlockStoreJSON {
  148. bytes := db.Get(blockStoreKey)
  149. if bytes == nil {
  150. return BlockStoreJSON{
  151. Height: 0,
  152. }
  153. }
  154. bsj := BlockStoreJSON{}
  155. err := json.Unmarshal(bytes, &bsj)
  156. if err != nil {
  157. Panicf("Could not unmarshal bytes: %X", bytes)
  158. }
  159. return bsj
  160. }