8 log "github.com/sirupsen/logrus"
9 "github.com/tendermint/tmlibs/common"
11 dbm "github.com/bytom/bytom/database/leveldb"
12 "github.com/bytom/bytom/database/storage"
13 "github.com/bytom/bytom/errors"
14 "github.com/bytom/bytom/protocol"
15 "github.com/bytom/bytom/protocol/bc"
16 "github.com/bytom/bytom/protocol/bc/types"
17 "github.com/bytom/bytom/protocol/state"
20 const logModule = "leveldb"
23 // CheckpointPrefix represent the namespace of checkpoints in db
24 CheckpointPrefix = []byte("CP:")
25 // BlockStoreKey block store key
26 BlockStoreKey = []byte("blockStore")
27 // BlockHeaderIndexPrefix block header index with height
28 BlockHeaderIndexPrefix = []byte("BH:")
31 func loadBlockStoreStateJSON(db dbm.DB) *protocol.BlockStoreState {
32 bytes := db.Get(BlockStoreKey)
36 bsj := &protocol.BlockStoreState{}
37 if err := json.Unmarshal(bytes, bsj); err != nil {
38 common.PanicCrisis(common.Fmt("Could not unmarshal bytes: %X", bytes))
43 // A Store encapsulates storage for blockchain validation.
44 // It satisfies the interface protocol.Store, and provides additional
45 // methods for querying current data.
51 // NewStore creates and returns a new Store object.
52 func NewStore(db dbm.DB) *Store {
53 fillBlockHeaderFn := func(hash *bc.Hash) (*types.BlockHeader, error) {
54 return GetBlockHeader(db, hash)
57 fillBlockTxsFn := func(hash *bc.Hash) ([]*types.Tx, error) {
58 return GetBlockTransactions(db, hash)
61 fillBlockHashesFn := func(height uint64) ([]*bc.Hash, error) {
62 return GetBlockHashesByHeight(db, height)
65 cache := newCache(fillBlockHeaderFn, fillBlockTxsFn, fillBlockHashesFn)
72 // GetBlockHeader return the BlockHeader by given hash
73 func (s *Store) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) {
74 return s.cache.lookupBlockHeader(hash)
77 // GetUtxo will search the utxo in db
78 func (s *Store) GetUtxo(hash *bc.Hash) (*storage.UtxoEntry, error) {
79 return getUtxo(s.db, hash)
82 func (s *Store) GetContract(hash [32]byte) ([]byte, error) {
83 return getContract(s.db, hash)
86 // BlockExist check if the block is stored in disk
87 func (s *Store) BlockExist(hash *bc.Hash) bool {
88 _, err := s.cache.lookupBlockHeader(hash)
92 // SaveBlockHeader persists a new block header in the protocol.
93 func (s *Store) SaveBlockHeader(blockHeader *types.BlockHeader) error {
94 binaryBlockHeader, err := blockHeader.MarshalText()
96 return errors.Wrap(err, "Marshal block header")
99 blockHash := blockHeader.Hash()
100 s.db.Set(CalcBlockHeaderKey(&blockHash), binaryBlockHeader)
101 s.cache.removeBlockHeader(blockHeader)
105 // GetBlockHashesByHeight return the block hash by the specified height
106 func (s *Store) GetBlockHashesByHeight(height uint64) ([]*bc.Hash, error) {
107 return s.cache.lookupBlockHashesByHeight(height)
110 // SaveBlock persists a new block in the protocol.
111 func (s *Store) SaveBlock(block *types.Block) error {
112 startTime := time.Now()
113 binaryBlockHeader, err := block.MarshalTextForBlockHeader()
115 return errors.Wrap(err, "Marshal block header")
118 binaryBlockTxs, err := block.MarshalTextForTransactions()
120 return errors.Wrap(err, "Marshal block transactions")
123 blockHashes := []*bc.Hash{}
124 hashes, err := s.GetBlockHashesByHeight(block.Height)
129 blockHashes = append(blockHashes, hashes...)
130 blockHash := block.Hash()
131 blockHashes = append(blockHashes, &blockHash)
132 binaryBlockHashes, err := json.Marshal(blockHashes)
134 return errors.Wrap(err, "Marshal block hashes")
137 batch := s.db.NewBatch()
138 batch.Set(CalcBlockHashesKey(block.Height), binaryBlockHashes)
139 batch.Set(CalcBlockHeaderKey(&blockHash), binaryBlockHeader)
140 batch.Set(CalcBlockTransactionsKey(&blockHash), binaryBlockTxs)
141 batch.Set(CalcBlockHeaderIndexKey(block.Height, &blockHash), binaryBlockHeader)
144 s.cache.removeBlockHashes(block.Height)
145 log.WithFields(log.Fields{
147 "height": block.Height,
148 "hash": blockHash.String(),
149 "duration": time.Since(startTime),
150 }).Info("block saved on disk")
154 // GetBlockTransactions return the Block transactions by given hash
155 func (s *Store) GetBlockTransactions(hash *bc.Hash) ([]*types.Tx, error) {
156 return s.cache.lookupBlockTxs(hash)
159 // GetBlock return the block by given hash
160 func (s *Store) GetBlock(hash *bc.Hash) (*types.Block, error) {
161 blockHeader, err := s.GetBlockHeader(hash)
166 txs, err := s.GetBlockTransactions(hash)
172 BlockHeader: *blockHeader,
177 // GetTransactionsUtxo will return all the utxo that related to the input txs
178 func (s *Store) GetTransactionsUtxo(view *state.UtxoViewpoint, txs []*bc.Tx) error {
179 return getTransactionsUtxo(s.db, view, txs)
182 // GetStoreStatus return the BlockStoreStateJSON
183 func (s *Store) GetStoreStatus() *protocol.BlockStoreState {
184 return loadBlockStoreStateJSON(s.db)
187 // LoadBlockIndex loadblockIndex by bestHeight
188 func (s *Store) LoadBlockIndex(stateBestHeight uint64) (*state.BlockIndex, error) {
189 startTime := time.Now()
190 blockIndex := state.NewBlockIndex()
191 bhIter := s.db.IteratorPrefix(BlockHeaderIndexPrefix)
192 defer bhIter.Release()
194 var lastNode *state.BlockNode
196 bh := &types.BlockHeader{}
197 if err := bh.UnmarshalText(bhIter.Value()); err != nil {
201 // If a block with a height greater than the best height of state is added to the index,
202 // It may cause a bug that the new block cant not be process properly.
203 if bh.Height > stateBestHeight {
207 var parent *state.BlockNode
208 if lastNode == nil || lastNode.Hash == bh.PreviousBlockHash {
211 parent = blockIndex.GetNode(&bh.PreviousBlockHash)
214 node, err := state.NewBlockNode(bh, parent)
219 blockIndex.AddNode(node)
223 log.WithFields(log.Fields{
225 "height": stateBestHeight,
226 "duration": time.Since(startTime),
227 }).Debug("initialize load history block index from database")
228 return blockIndex, nil
231 // SaveChainStatus save the core's newest status && delete old status
232 func (s *Store) SaveChainStatus(node *state.BlockNode, view *state.UtxoViewpoint, contractView *state.ContractViewpoint, finalizedHeight uint64, finalizedHash *bc.Hash) error {
233 batch := s.db.NewBatch()
234 if err := saveUtxoView(batch, view); err != nil {
238 if err := deleteContractView(s.db, batch, contractView); err != nil {
242 if err := saveContractView(s.db, batch, contractView); err != nil {
246 bytes, err := json.Marshal(protocol.BlockStoreState{Height: node.Height, Hash: &node.Hash, FinalizedHeight: finalizedHeight, FinalizedHash: finalizedHash})
251 batch.Set(BlockStoreKey, bytes)
256 func calcCheckpointKey(height uint64, hash *bc.Hash) []byte {
257 buf := make([]byte, 8)
258 binary.BigEndian.PutUint64(buf, height)
259 key := append(CheckpointPrefix, buf...)
261 key = append(key, hash.Bytes()...)
266 func (s *Store) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error) {
267 header, err := s.GetBlockHeader(hash)
272 data := s.db.Get(calcCheckpointKey(header.Height, hash))
273 checkpoint := &state.Checkpoint{}
274 if err := json.Unmarshal(data, checkpoint); err != nil {
278 return checkpoint, nil
281 // GetCheckpointsByHeight return all checkpoints of specified block height
282 func (s *Store) GetCheckpointsByHeight(height uint64) ([]*state.Checkpoint, error) {
283 iter := s.db.IteratorPrefix(calcCheckpointKey(height, nil))
285 return loadCheckpointsFromIter(iter)
288 // CheckpointsFromNode return all checkpoints from specified block height and hash
289 func (s *Store) CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error) {
290 startKey := calcCheckpointKey(height, hash)
291 iter := s.db.IteratorPrefixWithStart(CheckpointPrefix, startKey, false)
293 finalizedCheckpoint := &state.Checkpoint{}
294 if err := json.Unmarshal(iter.Value(), finalizedCheckpoint); err != nil {
298 checkpoints := []*state.Checkpoint{finalizedCheckpoint}
299 subs, err := loadCheckpointsFromIter(iter)
304 checkpoints = append(checkpoints, subs...)
305 return checkpoints, nil
308 func loadCheckpointsFromIter(iter dbm.Iterator) ([]*state.Checkpoint, error) {
309 var checkpoints []*state.Checkpoint
312 checkpoint := &state.Checkpoint{}
313 if err := json.Unmarshal(iter.Value(), checkpoint); err != nil {
317 checkpoints = append(checkpoints, checkpoint)
319 return checkpoints, nil
322 // SaveCheckpoints bulk save multiple checkpoint
323 func (s *Store) SaveCheckpoints(checkpoints ...*state.Checkpoint) error {
324 batch := s.db.NewBatch()
325 for _, checkpoint := range checkpoints {
326 data, err := json.Marshal(checkpoint)
331 batch.Set(calcCheckpointKey(checkpoint.Height, &checkpoint.Hash), data)