tendermint/blocks/store.go

103 lines
2.2 KiB
Go
Raw Normal View History

2014-08-10 16:35:08 -07:00
package blocks
import (
"bytes"
"encoding/binary"
"encoding/json"
. "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common"
2014-10-18 01:42:33 -07:00
db_ "github.com/tendermint/tendermint/db"
2014-08-10 16:35:08 -07:00
)
var (
blockStoreKey = []byte("blockStore")
)
//-----------------------------------------------------------------------------
type BlockStoreJSON struct {
Height uint32
}
2014-10-18 01:42:33 -07:00
func (bsj BlockStoreJSON) Save(db db_.DB) {
2014-08-10 16:35:08 -07:00
bytes, err := json.Marshal(bsj)
if err != nil {
Panicf("Could not marshal state bytes: %v", err)
}
2014-10-18 01:42:33 -07:00
db.Set(blockStoreKey, bytes)
2014-08-10 16:35:08 -07:00
}
2014-10-18 01:42:33 -07:00
func LoadBlockStoreJSON(db db_.DB) BlockStoreJSON {
bytes := db.Get(blockStoreKey)
2014-08-10 16:35:08 -07:00
if bytes == nil {
return BlockStoreJSON{
Height: 0,
}
}
bsj := BlockStoreJSON{}
2014-10-18 01:42:33 -07:00
err := json.Unmarshal(bytes, &bsj)
2014-08-10 16:35:08 -07:00
if err != nil {
Panicf("Could not unmarshal bytes: %X", bytes)
}
return bsj
}
//-----------------------------------------------------------------------------
/*
Simple low level store for blocks, which is actually stored as separte parts (wire format).
*/
type BlockStore struct {
height uint32
2014-10-18 01:42:33 -07:00
db db_.DB
2014-08-10 16:35:08 -07:00
}
2014-10-18 01:42:33 -07:00
func NewBlockStore(db db_.DB) *BlockStore {
2014-08-10 16:35:08 -07:00
bsjson := LoadBlockStoreJSON(db)
return &BlockStore{
height: bsjson.Height,
db: db,
}
}
// Height() returns the last known contiguous block height.
func (bs *BlockStore) Height() uint32 {
return bs.height
}
2014-09-14 15:37:32 -07:00
func (bs *BlockStore) LoadBlock(height uint32) *Block {
2014-10-18 01:42:33 -07:00
blockBytes := bs.db.Get(calcBlockKey(height))
2014-09-14 15:37:32 -07:00
if blockBytes == nil {
2014-08-10 16:35:08 -07:00
return nil
}
var n int64
2014-10-18 01:42:33 -07:00
var err error
block := ReadBlock(bytes.NewReader(blockBytes), &n, &err)
if err != nil {
Panicf("Error reading block: %v", err)
}
return block
2014-08-10 16:35:08 -07:00
}
// Writes are synchronous and atomic.
2014-10-18 01:42:33 -07:00
func (bs *BlockStore) SaveBlock(block *Block) {
2014-09-14 15:37:32 -07:00
height := block.Height
2014-08-10 16:35:08 -07:00
if height != bs.height+1 {
2014-10-18 01:42:33 -07:00
Panicf("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.height+1, height)
2014-08-10 16:35:08 -07:00
}
2014-09-14 15:37:32 -07:00
// Save block
blockBytes := BinaryBytes(block)
2014-10-18 01:42:33 -07:00
bs.db.Set(calcBlockKey(height), blockBytes)
2014-08-10 16:35:08 -07:00
// Save new BlockStoreJSON descriptor
BlockStoreJSON{Height: height}.Save(bs.db)
}
//-----------------------------------------------------------------------------
2014-09-14 15:37:32 -07:00
func calcBlockKey(height uint32) []byte {
buf := [9]byte{'B'}
2014-08-10 16:35:08 -07:00
binary.BigEndian.PutUint32(buf[1:9], height)
return buf[:]
}