tendermint/blockchain/store.go

232 lines
6.3 KiB
Go
Raw Normal View History

package blockchain
2014-08-10 16:35:08 -07:00
import (
"bytes"
"encoding/json"
"fmt"
"io"
2014-08-10 16:35:08 -07:00
2015-04-01 17:30:16 -07:00
"github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common"
dbm "github.com/tendermint/tendermint/db"
"github.com/tendermint/tendermint/types"
2014-08-10 16:35:08 -07:00
)
/*
2014-12-23 01:35:54 -08:00
Simple low level store for blocks.
There are three types of information stored:
- BlockMeta: Meta information about each block
- Block part: Parts of each block, aggregated w/ PartSet
2015-06-05 14:15:40 -07:00
- Validation: The Validation part of each block, for gossiping precommit votes
2014-12-23 01:35:54 -08:00
2015-06-05 14:15:40 -07:00
Currently the precommit signatures are duplicated in the Block parts as
2014-12-23 01:35:54 -08:00
well as the Validation. In the future this may change, perhaps by moving
the Validation data outside the Block.
2015-06-16 21:16:58 -07:00
Panics indicate probable corruption in the data
2014-08-10 16:35:08 -07:00
*/
type BlockStore struct {
height int
db dbm.DB
2014-08-10 16:35:08 -07:00
}
func NewBlockStore(db dbm.DB) *BlockStore {
2014-12-23 01:35:54 -08:00
bsjson := LoadBlockStoreStateJSON(db)
2014-08-10 16:35:08 -07:00
return &BlockStore{
height: bsjson.Height,
db: db,
}
}
// Height() returns the last known contiguous block height.
func (bs *BlockStore) Height() int {
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 int) *types.Block {
var n int64
2014-10-18 01:42:33 -07:00
var err error
2015-01-07 01:15:39 -08:00
r := bs.GetReader(calcBlockMetaKey(height))
if r == nil {
2015-06-16 21:16:58 -07:00
return nil
2015-01-07 01:15:39 -08:00
}
meta := binary.ReadBinary(&types.BlockMeta{}, r, &n, &err).(*types.BlockMeta)
if err != nil {
2015-07-19 16:42:52 -07:00
PanicCrisis(Fmt("Error reading block meta: %v", err))
}
bytez := []byte{}
for i := 0; i < meta.PartsHeader.Total; i++ {
part := bs.LoadBlockPart(height, i)
bytez = append(bytez, part.Bytes...)
}
block := binary.ReadBinary(&types.Block{}, bytes.NewReader(bytez), &n, &err).(*types.Block)
2014-10-18 01:42:33 -07:00
if err != nil {
2015-07-19 16:42:52 -07:00
PanicCrisis(Fmt("Error reading block: %v", err))
2014-10-18 01:42:33 -07:00
}
return block
2014-08-10 16:35:08 -07:00
}
func (bs *BlockStore) LoadBlockPart(height int, index int) *types.Part {
var n int64
var err error
2015-01-07 01:15:39 -08:00
r := bs.GetReader(calcBlockPartKey(height, index))
if r == nil {
2015-06-16 21:16:58 -07:00
return nil
2015-01-07 01:15:39 -08:00
}
part := binary.ReadBinary(&types.Part{}, r, &n, &err).(*types.Part)
if err != nil {
2015-07-19 16:42:52 -07:00
PanicCrisis(Fmt("Error reading block part: %v", err))
}
return part
}
func (bs *BlockStore) LoadBlockMeta(height int) *types.BlockMeta {
var n int64
var err error
2015-01-07 01:15:39 -08:00
r := bs.GetReader(calcBlockMetaKey(height))
if r == nil {
2015-06-16 21:16:58 -07:00
return nil
2015-01-07 01:15:39 -08:00
}
meta := binary.ReadBinary(&types.BlockMeta{}, r, &n, &err).(*types.BlockMeta)
if err != nil {
2015-07-19 16:42:52 -07:00
PanicCrisis(Fmt("Error reading block meta: %v", err))
}
return meta
}
2015-06-19 15:30:10 -07:00
// The +2/3 and other Precommit-votes for block at `height`.
// This Validation comes from block.LastValidation for `height+1`.
func (bs *BlockStore) LoadBlockValidation(height int) *types.Validation {
var n int64
var err error
2015-01-07 01:15:39 -08:00
r := bs.GetReader(calcBlockValidationKey(height))
if r == nil {
2015-06-16 21:16:58 -07:00
return nil
2015-01-07 01:15:39 -08:00
}
validation := binary.ReadBinary(&types.Validation{}, r, &n, &err).(*types.Validation)
if err != nil {
2015-07-19 16:42:52 -07:00
PanicCrisis(Fmt("Error reading validation: %v", err))
}
return validation
}
2015-06-05 14:15:40 -07:00
// NOTE: the Precommit-vote heights are for the block at `height`
func (bs *BlockStore) LoadSeenValidation(height int) *types.Validation {
var n int64
var err error
r := bs.GetReader(calcSeenValidationKey(height))
if r == nil {
2015-06-16 21:16:58 -07:00
return nil
}
validation := binary.ReadBinary(&types.Validation{}, r, &n, &err).(*types.Validation)
if err != nil {
2015-07-19 16:42:52 -07:00
PanicCrisis(Fmt("Error reading validation: %v", err))
}
return validation
}
// blockParts: Must be parts of the block
2015-06-05 14:15:40 -07:00
// seenValidation: The +2/3 precommits that were seen which committed at height.
// If all the nodes restart after committing a block,
2015-06-05 14:15:40 -07:00
// we need this to reload the precommits to catch-up nodes to the
// most recent height. Otherwise they'd stall at H-1.
func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenValidation *types.Validation) {
2014-09-14 15:37:32 -07:00
height := block.Height
2014-08-10 16:35:08 -07:00
if height != bs.height+1 {
2015-07-19 16:42:52 -07:00
PanicSanity(Fmt("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() {
2015-07-19 16:42:52 -07:00
PanicSanity(Fmt("BlockStore can only save complete block part sets"))
}
2014-12-23 01:35:54 -08:00
// Save block meta
meta := types.NewBlockMeta(block, blockParts)
metaBytes := binary.BinaryBytes(meta)
bs.db.Set(calcBlockMetaKey(height), metaBytes)
2014-12-23 01:35:54 -08:00
// Save block parts
for i := 0; i < blockParts.Total(); i++ {
bs.saveBlockPart(height, i, blockParts.GetPart(i))
}
2014-12-23 01:35:54 -08:00
// Save block validation (duplicate and separate from the Block)
2015-06-19 15:30:10 -07:00
blockValidationBytes := binary.BinaryBytes(block.LastValidation)
bs.db.Set(calcBlockValidationKey(height-1), blockValidationBytes)
2015-06-05 14:15:40 -07:00
// Save seen validation (seen +2/3 precommits for block)
seenValidationBytes := binary.BinaryBytes(seenValidation)
bs.db.Set(calcSeenValidationKey(height), seenValidationBytes)
2014-12-23 01:35:54 -08:00
// Save new BlockStoreStateJSON descriptor
BlockStoreStateJSON{Height: height}.Save(bs.db)
// Done!
bs.height = height
2014-08-10 16:35:08 -07:00
}
func (bs *BlockStore) saveBlockPart(height int, index int, part *types.Part) {
if height != bs.height+1 {
2015-07-19 16:42:52 -07:00
PanicSanity(Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.height+1, height))
}
partBytes := binary.BinaryBytes(part)
bs.db.Set(calcBlockPartKey(height, index), partBytes)
}
//-----------------------------------------------------------------------------
func calcBlockMetaKey(height int) []byte {
return []byte(fmt.Sprintf("H:%v", height))
2014-08-10 16:35:08 -07:00
}
func calcBlockPartKey(height int, partIndex int) []byte {
return []byte(fmt.Sprintf("P:%v:%v", height, partIndex))
}
func calcBlockValidationKey(height int) []byte {
return []byte(fmt.Sprintf("V:%v", height))
}
func calcSeenValidationKey(height int) []byte {
return []byte(fmt.Sprintf("SV:%v", height))
}
//-----------------------------------------------------------------------------
var blockStoreKey = []byte("blockStore")
2014-12-23 01:35:54 -08:00
type BlockStoreStateJSON struct {
Height int
}
func (bsj BlockStoreStateJSON) Save(db dbm.DB) {
bytes, err := json.Marshal(bsj)
if err != nil {
2015-07-19 16:42:52 -07:00
PanicSanity(Fmt("Could not marshal state bytes: %v", err))
}
db.Set(blockStoreKey, bytes)
}
func LoadBlockStoreStateJSON(db dbm.DB) BlockStoreStateJSON {
bytes := db.Get(blockStoreKey)
if bytes == nil {
2014-12-23 01:35:54 -08:00
return BlockStoreStateJSON{
Height: 0,
}
}
2014-12-23 01:35:54 -08:00
bsj := BlockStoreStateJSON{}
err := json.Unmarshal(bytes, &bsj)
if err != nil {
2015-07-19 16:42:52 -07:00
PanicCrisis(Fmt("Could not unmarshal bytes: %X", bytes))
}
return bsj
}