OSDN Git Service

Revert "delete the crazy log"
[bytom/vapor.git] / database / store.go
index f1c2b23..3af6338 100644 (file)
@@ -21,10 +21,11 @@ import (
 const logModule = "leveldb"
 
 var (
-       blockStoreKey     = []byte("blockStore")
-       blockPrefix       = []byte("B:")
-       blockHeaderPrefix = []byte("BH:")
-       txStatusPrefix    = []byte("BTS:")
+       blockStoreKey          = []byte("blockStore")
+       blockHeaderPrefix      = []byte("BH:")
+       blockTransactonsPrefix = []byte("BTXS:")
+       txStatusPrefix         = []byte("BTS:")
+       voteResultPrefix       = []byte("VR:")
 )
 
 func loadBlockStoreStateJSON(db dbm.DB) *protocol.BlockStoreState {
@@ -47,10 +48,6 @@ type Store struct {
        cache blockCache
 }
 
-func calcBlockKey(hash *bc.Hash) []byte {
-       return append(blockPrefix, hash.Bytes()...)
-}
-
 func calcBlockHeaderKey(height uint64, hash *bc.Hash) []byte {
        buf := [8]byte{}
        binary.BigEndian.PutUint64(buf[:], height)
@@ -58,30 +55,77 @@ func calcBlockHeaderKey(height uint64, hash *bc.Hash) []byte {
        return append(key, hash.Bytes()...)
 }
 
+func calcBlockTransactionsKey(hash *bc.Hash) []byte {
+       return append(blockTransactonsPrefix, hash.Bytes()...)
+}
+
 func calcTxStatusKey(hash *bc.Hash) []byte {
        return append(txStatusPrefix, hash.Bytes()...)
 }
 
-// GetBlock return the block by given hash
-func GetBlock(db dbm.DB, hash *bc.Hash) (*types.Block, error) {
-       bytez := db.Get(calcBlockKey(hash))
-       if bytez == nil {
+func calcVoteResultKey(seq uint64) []byte {
+       buf := [8]byte{}
+       binary.BigEndian.PutUint64(buf[:], seq)
+       return append(voteResultPrefix, buf[:]...)
+}
+
+// GetBlockHeader return the block header by given hash and height
+func GetBlockHeader(db dbm.DB, hash *bc.Hash, height uint64) (*types.BlockHeader, error) {
+       block := &types.Block{}
+       binaryBlockHeader := db.Get(calcBlockHeaderKey(height, hash))
+       if binaryBlockHeader == nil {
                return nil, nil
        }
+       if err := block.UnmarshalText(binaryBlockHeader); err != nil {
+               return nil, err
+       }
+
+       return &block.BlockHeader, nil
+}
 
+// GetBlockTransactions return the block transactions by given hash
+func GetBlockTransactions(db dbm.DB, hash *bc.Hash) ([]*types.Tx, error) {
        block := &types.Block{}
-       err := block.UnmarshalText(bytez)
-       return block, err
+       binaryBlockTxs := db.Get(calcBlockTransactionsKey(hash))
+       if binaryBlockTxs == nil {
+               return nil, errors.New("The transactions in the block is empty")
+       }
+
+       if err := block.UnmarshalText(binaryBlockTxs); err != nil {
+               return nil, err
+       }
+       return block.Transactions, nil
+}
+
+// GetVoteResult return the vote result by given sequence
+func GetVoteResult(db dbm.DB, seq uint64) (*state.VoteResult, error) {
+       data := db.Get(calcVoteResultKey(seq))
+       if data == nil {
+               return nil, protocol.ErrNotFoundVoteResult
+       }
+
+       voteResult := new(state.VoteResult)
+       if err := json.Unmarshal(data, voteResult); err != nil {
+               return nil, errors.Wrap(err, "unmarshaling vote result")
+       }
+       return voteResult, nil
 }
 
 // NewStore creates and returns a new Store object.
 func NewStore(db dbm.DB) *Store {
-       cache := newBlockCache(func(hash *bc.Hash) (*types.Block, error) {
-               return GetBlock(db, hash)
-       })
+       fillBlockHeaderFn := func(hash *bc.Hash, height uint64) (*types.BlockHeader, error) {
+               return GetBlockHeader(db, hash, height)
+       }
+       fillBlockTxsFn := func(hash *bc.Hash) ([]*types.Tx, error) {
+               return GetBlockTransactions(db, hash)
+       }
+       fillVoteResultFn := func(seq uint64) (*state.VoteResult, error) {
+               return GetVoteResult(db, seq)
+       }
+       bc := newBlockCache(fillBlockHeaderFn, fillBlockTxsFn, fillVoteResultFn)
        return &Store{
                db:    db,
-               cache: cache,
+               cache: bc,
        }
 }
 
@@ -91,14 +135,45 @@ func (s *Store) GetUtxo(hash *bc.Hash) (*storage.UtxoEntry, error) {
 }
 
 // BlockExist check if the block is stored in disk
-func (s *Store) BlockExist(hash *bc.Hash) bool {
-       block, err := s.cache.lookup(hash)
-       return err == nil && block != nil
+func (s *Store) BlockExist(hash *bc.Hash, height uint64) bool {
+       blockHeader, err := s.cache.lookupBlockHeader(hash, height)
+       return err == nil && blockHeader != nil
 }
 
 // GetBlock return the block by given hash
-func (s *Store) GetBlock(hash *bc.Hash) (*types.Block, error) {
-       return s.cache.lookup(hash)
+func (s *Store) GetBlock(hash *bc.Hash, height uint64) (*types.Block, error) {
+       blockHeader, err := s.GetBlockHeader(hash, height)
+       if err != nil {
+               return nil, err
+       }
+
+       txs, err := s.GetBlockTransactions(hash)
+       if err != nil {
+               return nil, err
+       }
+
+       return &types.Block{
+               BlockHeader:  *blockHeader,
+               Transactions: txs,
+       }, nil
+}
+
+// GetBlockHeader return the BlockHeader by given hash
+func (s *Store) GetBlockHeader(hash *bc.Hash, height uint64) (*types.BlockHeader, error) {
+       blockHeader, err := s.cache.lookupBlockHeader(hash, height)
+       if err != nil {
+               return nil, err
+       }
+       return blockHeader, nil
+}
+
+// GetBlockTransactions return the Block transactions by given hash
+func (s *Store) GetBlockTransactions(hash *bc.Hash) ([]*types.Tx, error) {
+       txs, err := s.cache.lookupBlockTxs(hash)
+       if err != nil {
+               return nil, err
+       }
+       return txs, nil
 }
 
 // GetTransactionsUtxo will return all the utxo that related to the input txs
@@ -125,6 +200,11 @@ func (s *Store) GetStoreStatus() *protocol.BlockStoreState {
        return loadBlockStoreStateJSON(s.db)
 }
 
+// GetVoteResult retrive the voting result in specified vote sequence
+func (s *Store) GetVoteResult(seq uint64) (*state.VoteResult, error) {
+       return s.cache.lookupVoteResult(seq)
+}
+
 func (s *Store) LoadBlockIndex(stateBestHeight uint64) (*state.BlockIndex, error) {
        startTime := time.Now()
        blockIndex := state.NewBlockIndex()
@@ -171,14 +251,15 @@ func (s *Store) LoadBlockIndex(stateBestHeight uint64) (*state.BlockIndex, error
 // SaveBlock persists a new block in the protocol.
 func (s *Store) SaveBlock(block *types.Block, ts *bc.TransactionStatus) error {
        startTime := time.Now()
-       binaryBlock, err := block.MarshalText()
+
+       binaryBlockHeader, err := block.MarshalTextForBlockHeader()
        if err != nil {
-               return errors.Wrap(err, "Marshal block meta")
+               return errors.Wrap(err, "Marshal block header")
        }
 
-       binaryBlockHeader, err := block.BlockHeader.MarshalText()
+       binaryBlockTxs, err := block.MarshalTextForTransactions()
        if err != nil {
-               return errors.Wrap(err, "Marshal block header")
+               return errors.Wrap(err, "Marshal block transactions")
        }
 
        binaryTxStatus, err := proto.Marshal(ts)
@@ -188,8 +269,8 @@ func (s *Store) SaveBlock(block *types.Block, ts *bc.TransactionStatus) error {
 
        blockHash := block.Hash()
        batch := s.db.NewBatch()
-       batch.Set(calcBlockKey(&blockHash), binaryBlock)
        batch.Set(calcBlockHeaderKey(block.Height, &blockHash), binaryBlockHeader)
+       batch.Set(calcBlockTransactionsKey(&blockHash), binaryBlockTxs)
        batch.Set(calcTxStatusKey(&blockHash), binaryTxStatus)
        batch.Write()
 
@@ -202,14 +283,57 @@ func (s *Store) SaveBlock(block *types.Block, ts *bc.TransactionStatus) error {
        return nil
 }
 
+// SaveBlockHeader persists a new block header in the protocol.
+func (s *Store) SaveBlockHeader(blockHeader *types.BlockHeader) error {
+       startTime := time.Now()
+
+       binaryBlockHeader, err := blockHeader.MarshalText()
+       if err != nil {
+               return errors.Wrap(err, "Marshal block header")
+       }
+
+       blockHash := blockHeader.Hash()
+       s.db.Set(calcBlockHeaderKey(blockHeader.Height, &blockHash), binaryBlockHeader)
+
+       // updata blockheader cache
+       if _, ok := s.cache.getBlockHeader(&blockHash); ok {
+               s.cache.addBlockHeader(blockHeader)
+       }
+
+       log.WithFields(log.Fields{
+               "module":   logModule,
+               "height":   blockHeader.Height,
+               "hash":     blockHash.String(),
+               "duration": time.Since(startTime),
+       }).Info("blockHeader saved on disk")
+       return nil
+}
+
 // SaveChainStatus save the core's newest status && delete old status
-func (s *Store) SaveChainStatus(node *state.BlockNode, view *state.UtxoViewpoint) error {
+func (s *Store) SaveChainStatus(node, irreversibleNode *state.BlockNode, view *state.UtxoViewpoint, voteResults []*state.VoteResult) error {
        batch := s.db.NewBatch()
        if err := saveUtxoView(batch, view); err != nil {
                return err
        }
 
-       bytes, err := json.Marshal(protocol.BlockStoreState{Height: node.Height, Hash: &node.Hash})
+       for _, vote := range voteResults {
+               bytes, err := json.Marshal(vote)
+               if err != nil {
+                       return err
+               }
+
+               batch.Set(calcVoteResultKey(vote.Seq), bytes)
+               if _, ok := s.cache.getVoteResult(vote.Seq); ok {
+                       s.cache.addVoteResult(vote)
+               }
+       }
+
+       bytes, err := json.Marshal(protocol.BlockStoreState{
+               Height:             node.Height,
+               Hash:               &node.Hash,
+               IrreversibleHeight: irreversibleNode.Height,
+               IrreversibleHash:   &irreversibleNode.Hash,
+       })
        if err != nil {
                return err
        }