tendermint/blocks/store.go

183 lines
4.6 KiB
Go
Raw Normal View History

2014-08-10 16:35:08 -07:00
package blocks
import (
"bytes"
"encoding/json"
"fmt"
"io"
2014-08-10 16:35:08 -07:00
. "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
)
//-----------------------------------------------------------------------------
/*
Simple low level store for blocks, which is actually stored as separte parts (wire format).
*/
type BlockStore struct {
height uint
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() uint {
2014-08-10 16:35:08 -07:00
return bs.height
}
func (bs *BlockStore) GetReader(key []byte) io.Reader {
bytez := bs.db.Get(key)
if bytez == nil {
2014-08-10 16:35:08 -07:00
return nil
}
return bytes.NewReader(bytez)
}
func (bs *BlockStore) LoadBlock(height uint) *Block {
var n int64
2014-10-18 01:42:33 -07:00
var err error
meta := ReadBinary(&BlockMeta{}, bs.GetReader(calcBlockMetaKey(height)), &n, &err).(*BlockMeta)
if err != nil {
Panicf("Error reading block meta: %v", err)
}
bytez := []byte{}
for i := uint(0); i < meta.Parts.Total; i++ {
part := bs.LoadBlockPart(height, i)
bytez = append(bytez, part.Bytes...)
}
block := ReadBinary(&Block{}, bytes.NewReader(bytez), &n, &err).(*Block)
2014-10-18 01:42:33 -07:00
if err != nil {
Panicf("Error reading block: %v", err)
}
return block
2014-08-10 16:35:08 -07:00
}
func (bs *BlockStore) LoadBlockPart(height uint, index uint) *Part {
var n int64
var err error
part := ReadBinary(&Part{}, bs.GetReader(calcBlockPartKey(height, index)), &n, &err).(*Part)
if err != nil {
Panicf("Error reading block part: %v", err)
}
return part
}
func (bs *BlockStore) LoadBlockMeta(height uint) *BlockMeta {
var n int64
var err error
meta := ReadBinary(&BlockMeta{}, bs.GetReader(calcBlockMetaKey(height)), &n, &err).(*BlockMeta)
if err != nil {
Panicf("Error reading block meta: %v", err)
}
return meta
}
func (bs *BlockStore) LoadBlockValidation(height uint) *Validation {
var n int64
var err error
validation := ReadBinary(&Validation{}, bs.GetReader(calcBlockValidationKey(height)), &n, &err).(*Validation)
if err != nil {
Panicf("Error reading validation: %v", err)
}
return validation
}
func (bs *BlockStore) SaveBlock(block *Block, blockParts *PartSet) {
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
}
if !blockParts.IsComplete() {
Panicf("BlockStore can only save complete block part sets")
}
meta := &BlockMeta{
Hash: block.Hash(),
Parts: blockParts.Header(),
Header: block.Header,
}
// Save block meta
metaBytes := BinaryBytes(meta)
bs.db.Set(calcBlockMetaKey(height), metaBytes)
// Save block parts
for i := uint(0); i < blockParts.Total(); i++ {
bs.saveBlockPart(height, i, blockParts.GetPart(i))
}
// Save block validation (duplicate and separate)
validationBytes := BinaryBytes(block.Validation)
bs.db.Set(calcBlockValidationKey(height), validationBytes)
2014-08-10 16:35:08 -07:00
// Save new BlockStoreJSON descriptor
BlockStoreJSON{Height: height}.Save(bs.db)
// Done!
bs.height = height
2014-08-10 16:35:08 -07:00
}
func (bs *BlockStore) saveBlockPart(height uint, index uint, part *Part) {
if height != bs.height+1 {
Panicf("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.height+1, height)
}
partBytes := BinaryBytes(part)
bs.db.Set(calcBlockPartKey(height, index), partBytes)
}
//-----------------------------------------------------------------------------
type BlockMeta struct {
Hash []byte // The BlockHash
Parts PartSetHeader // The PartSetHeader, for transfer
Header *Header // The block's Header
}
2014-08-10 16:35:08 -07:00
//-----------------------------------------------------------------------------
func calcBlockMetaKey(height uint) []byte {
return []byte(fmt.Sprintf("H:%v", height))
2014-08-10 16:35:08 -07:00
}
func calcBlockPartKey(height uint, partIndex uint) []byte {
return []byte(fmt.Sprintf("P:%v:%v", height, partIndex))
}
func calcBlockValidationKey(height uint) []byte {
return []byte(fmt.Sprintf("V:%v", height))
}
//-----------------------------------------------------------------------------
var blockStoreKey = []byte("blockStore")
type BlockStoreJSON struct {
Height uint
}
func (bsj BlockStoreJSON) Save(db db_.DB) {
bytes, err := json.Marshal(bsj)
if err != nil {
Panicf("Could not marshal state bytes: %v", err)
}
db.Set(blockStoreKey, bytes)
}
func LoadBlockStoreJSON(db db_.DB) BlockStoreJSON {
bytes := db.Get(blockStoreKey)
if bytes == nil {
return BlockStoreJSON{
Height: 0,
}
}
bsj := BlockStoreJSON{}
err := json.Unmarshal(bytes, &bsj)
if err != nil {
Panicf("Could not unmarshal bytes: %X", bytes)
}
return bsj
}