9 "github.com/golang/protobuf/proto"
10 log "github.com/sirupsen/logrus"
12 dbm "github.com/bytom/vapor/database/leveldb"
13 "github.com/bytom/vapor/database/storage"
14 "github.com/bytom/vapor/errors"
15 "github.com/bytom/vapor/protocol"
16 "github.com/bytom/vapor/protocol/bc"
17 "github.com/bytom/vapor/protocol/bc/types"
18 "github.com/bytom/vapor/protocol/state"
24 // the byte of colon(:)
29 blockStore byte = iota
38 func loadBlockStoreStateJSON(db dbm.DB) *protocol.BlockStoreState {
39 bytes := db.Get([]byte{blockStore})
44 bsj := &protocol.BlockStoreState{}
45 if err := json.Unmarshal(bytes, bsj); err != nil {
46 log.WithField("err", err).Panic("fail on unmarshal BlockStoreStateJSON")
51 // A Store encapsulates storage for blockchain validation.
52 // It satisfies the interface protocol.Store, and provides additional
53 // methods for querying current data.
59 func calcMainChainIndexPrefix(height uint64) []byte {
61 binary.BigEndian.PutUint64(buf[:], height)
62 return append([]byte{mainChainIndex, colon}, buf[:]...)
65 func calcBlockHashesPrefix(height uint64) []byte {
67 binary.BigEndian.PutUint64(buf[:], height)
68 return append([]byte{blockHashes, colon}, buf[:]...)
71 func calcBlockHeaderKey(hash *bc.Hash) []byte {
72 return append([]byte{blockHeader, colon}, hash.Bytes()...)
75 func calcBlockTransactionsKey(hash *bc.Hash) []byte {
76 return append([]byte{blockTransactons, colon}, hash.Bytes()...)
79 func calcTxStatusKey(hash *bc.Hash) []byte {
80 return append([]byte{txStatus, colon}, hash.Bytes()...)
83 func calcConsensusResultKey(seq uint64) []byte {
85 binary.BigEndian.PutUint64(buf[:], seq)
86 return append([]byte{consensusResult, colon}, buf[:]...)
89 // GetBlockHeader return the block header by given hash
90 func GetBlockHeader(db dbm.DB, hash *bc.Hash) (*types.BlockHeader, error) {
91 binaryBlockHeader := db.Get(calcBlockHeaderKey(hash))
92 if binaryBlockHeader == nil {
93 return nil, fmt.Errorf("There are no blockHeader with given hash %s", hash.String())
96 blockHeader := &types.BlockHeader{}
97 if err := blockHeader.UnmarshalText(binaryBlockHeader); err != nil {
100 return blockHeader, nil
103 // GetBlockTransactions return the block transactions by given hash
104 func GetBlockTransactions(db dbm.DB, hash *bc.Hash) ([]*types.Tx, error) {
105 binaryBlockTxs := db.Get(calcBlockTransactionsKey(hash))
106 if binaryBlockTxs == nil {
107 return nil, fmt.Errorf("There are no block transactions with given hash %s", hash.String())
110 block := &types.Block{}
111 if err := block.UnmarshalText(binaryBlockTxs); err != nil {
114 return block.Transactions, nil
117 // GetBlockHashesByHeight return block hashes by given height
118 func GetBlockHashesByHeight(db dbm.DB, height uint64) ([]*bc.Hash, error) {
119 binaryHashes := db.Get(calcBlockHashesPrefix(height))
120 if binaryHashes == nil {
121 return []*bc.Hash{}, nil
124 hashes := []*bc.Hash{}
125 if err := json.Unmarshal(binaryHashes, &hashes); err != nil {
131 // GetMainChainHash return BlockHash by given height
132 func GetMainChainHash(db dbm.DB, height uint64) (*bc.Hash, error) {
133 binaryHash := db.Get(calcMainChainIndexPrefix(height))
134 if binaryHash == nil {
135 return nil, fmt.Errorf("There are no BlockHash with given height %d", height)
139 if err := hash.UnmarshalText(binaryHash); err != nil {
145 // GetConsensusResult return the vote result by given sequence
146 func GetConsensusResult(db dbm.DB, seq uint64) (*state.ConsensusResult, error) {
147 data := db.Get(calcConsensusResultKey(seq))
149 return nil, protocol.ErrNotFoundConsensusResult
152 consensusResult := new(state.ConsensusResult)
153 if err := json.Unmarshal(data, consensusResult); err != nil {
154 return nil, errors.Wrap(err, "unmarshaling vote result")
156 return consensusResult, nil
159 // DeleteConsensusResult delete a consensusResult from cache and database
160 func (s *Store) DeleteConsensusResult(seq uint64) error {
161 consensusResult, err := GetConsensusResult(s.db, seq)
166 s.db.Delete(calcConsensusResultKey(seq))
167 s.cache.removeConsensusResult(consensusResult)
171 // DeleteBlock delete a new block in the protocol.
172 func (s *Store) DeleteBlock(block *types.Block) error {
173 blockHash := block.Hash()
174 blockHashes, err := s.GetBlockHashesByHeight(block.Height)
179 for i := 0; i < len(blockHashes); i++ {
180 if blockHashes[i].String() == blockHash.String() {
181 blockHashes = append(blockHashes[0:i], blockHashes[i+1:len(blockHashes)]...)
186 batch := s.db.NewBatch()
187 if len(blockHashes) == 0 {
188 batch.Delete(calcBlockHashesPrefix(block.Height))
190 binaryBlockHashes, err := json.Marshal(blockHashes)
192 return errors.Wrap(err, "Marshal block hashes")
195 batch.Set(calcBlockHashesPrefix(block.Height), binaryBlockHashes)
198 batch.Delete(calcBlockHeaderKey(&blockHash))
199 batch.Delete(calcBlockTransactionsKey(&blockHash))
200 batch.Delete(calcTxStatusKey(&blockHash))
203 s.cache.removeBlockHashes(block.Height)
204 s.cache.removeBlockHeader(&block.BlockHeader)
209 // NewStore creates and returns a new Store object.
210 func NewStore(db dbm.DB) *Store {
211 fillBlockHeaderFn := func(hash *bc.Hash) (*types.BlockHeader, error) {
212 return GetBlockHeader(db, hash)
214 fillBlockTxsFn := func(hash *bc.Hash) ([]*types.Tx, error) {
215 return GetBlockTransactions(db, hash)
218 fillBlockHashesFn := func(height uint64) ([]*bc.Hash, error) {
219 return GetBlockHashesByHeight(db, height)
222 fillMainChainHashFn := func(height uint64) (*bc.Hash, error) {
223 return GetMainChainHash(db, height)
226 fillConsensusResultFn := func(seq uint64) (*state.ConsensusResult, error) {
227 return GetConsensusResult(db, seq)
230 cache := newCache(fillBlockHeaderFn, fillBlockTxsFn, fillBlockHashesFn, fillMainChainHashFn, fillConsensusResultFn)
237 // BlockExist check if the block is stored in disk
238 func (s *Store) BlockExist(hash *bc.Hash) bool {
239 _, err := s.cache.lookupBlockHeader(hash)
243 // GetBlock return the block by given hash
244 func (s *Store) GetBlock(hash *bc.Hash) (*types.Block, error) {
245 blockHeader, err := s.GetBlockHeader(hash)
250 txs, err := s.GetBlockTransactions(hash)
256 BlockHeader: *blockHeader,
261 // GetBlockHeader return the BlockHeader by given hash
262 func (s *Store) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) {
263 return s.cache.lookupBlockHeader(hash)
266 // GetBlockTransactions return the Block transactions by given hash
267 func (s *Store) GetBlockTransactions(hash *bc.Hash) ([]*types.Tx, error) {
268 return s.cache.lookupBlockTxs(hash)
271 // GetBlockHashesByHeight return the block hash by the specified height
272 func (s *Store) GetBlockHashesByHeight(height uint64) ([]*bc.Hash, error) {
273 return s.cache.lookupBlockHashesByHeight(height)
276 // GetMainChainHash return the block hash by the specified height
277 func (s *Store) GetMainChainHash(height uint64) (*bc.Hash, error) {
278 return s.cache.lookupMainChainHash(height)
281 // GetStoreStatus return the BlockStoreStateJSON
282 func (s *Store) GetStoreStatus() *protocol.BlockStoreState {
283 return loadBlockStoreStateJSON(s.db)
286 // GetTransactionsUtxo will return all the utxo that related to the input txs
287 func (s *Store) GetTransactionsUtxo(view *state.UtxoViewpoint, txs []*bc.Tx) error {
288 return getTransactionsUtxo(s.db, view, txs)
291 // GetTransactionStatus will return the utxo that related to the block hash
292 func (s *Store) GetTransactionStatus(hash *bc.Hash) (*bc.TransactionStatus, error) {
293 data := s.db.Get(calcTxStatusKey(hash))
295 return nil, errors.New("can't find the transaction status by given hash")
298 ts := &bc.TransactionStatus{}
299 if err := proto.Unmarshal(data, ts); err != nil {
300 return nil, errors.Wrap(err, "unmarshaling transaction status")
305 // GetUtxo will search the utxo in db
306 func (s *Store) GetUtxo(hash *bc.Hash) (*storage.UtxoEntry, error) {
307 return getUtxo(s.db, hash)
310 // GetConsensusResult retrive the voting result in specified vote sequence
311 func (s *Store) GetConsensusResult(seq uint64) (*state.ConsensusResult, error) {
312 return s.cache.lookupConsensusResult(seq)
315 // SaveBlock persists a new block in the protocol.
316 func (s *Store) SaveBlock(block *types.Block, ts *bc.TransactionStatus) error {
317 startTime := time.Now()
318 binaryBlockHeader, err := block.MarshalTextForBlockHeader()
320 return errors.Wrap(err, "Marshal block header")
323 binaryBlockTxs, err := block.MarshalTextForTransactions()
325 return errors.Wrap(err, "Marshal block transactions")
328 binaryTxStatus, err := proto.Marshal(ts)
330 return errors.Wrap(err, "Marshal block transaction status")
333 blockHashes := []*bc.Hash{}
334 hashes, err := s.GetBlockHashesByHeight(block.Height)
338 blockHashes = append(blockHashes, hashes...)
339 blockHash := block.Hash()
340 blockHashes = append(blockHashes, &blockHash)
341 binaryBlockHashes, err := json.Marshal(blockHashes)
343 return errors.Wrap(err, "Marshal block hashes")
346 batch := s.db.NewBatch()
347 batch.Set(calcBlockHashesPrefix(block.Height), binaryBlockHashes)
348 batch.Set(calcBlockHeaderKey(&blockHash), binaryBlockHeader)
349 batch.Set(calcBlockTransactionsKey(&blockHash), binaryBlockTxs)
350 batch.Set(calcTxStatusKey(&blockHash), binaryTxStatus)
353 s.cache.removeBlockHashes(block.Height)
354 log.WithFields(log.Fields{
356 "height": block.Height,
357 "hash": blockHash.String(),
358 "duration": time.Since(startTime),
359 }).Info("block saved on disk")
363 // SaveBlockHeader persists a new block header in the protocol.
364 func (s *Store) SaveBlockHeader(blockHeader *types.BlockHeader) error {
365 binaryBlockHeader, err := blockHeader.MarshalText()
367 return errors.Wrap(err, "Marshal block header")
370 blockHash := blockHeader.Hash()
371 s.db.Set(calcBlockHeaderKey(&blockHash), binaryBlockHeader)
372 s.cache.removeBlockHeader(blockHeader)
376 // SaveChainStatus save the core's newest status && delete old status
377 func (s *Store) SaveChainStatus(blockHeader, irrBlockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, consensusResults []*state.ConsensusResult) error {
378 currentStatus := loadBlockStoreStateJSON(s.db)
379 batch := s.db.NewBatch()
380 if err := saveUtxoView(batch, view); err != nil {
384 var clearCacheFuncs []func()
385 for _, consensusResult := range consensusResults {
386 result := consensusResult
387 bytes, err := json.Marshal(result)
392 batch.Set(calcConsensusResultKey(result.Seq), bytes)
393 clearCacheFuncs = append(clearCacheFuncs, func() {
394 s.cache.removeConsensusResult(result)
398 blockHash := blockHeader.Hash()
399 irrBlockHash := irrBlockHeader.Hash()
400 bytes, err := json.Marshal(protocol.BlockStoreState{
401 Height: blockHeader.Height,
403 IrreversibleHeight: irrBlockHeader.Height,
404 IrreversibleHash: &irrBlockHash,
409 batch.Set([]byte{blockStore}, bytes)
411 // save main chain blockHeaders
412 for _, blockHeader := range mainBlockHeaders {
414 blockHash := bh.Hash()
415 binaryBlockHash, err := blockHash.MarshalText()
417 return errors.Wrap(err, "Marshal block hash")
420 batch.Set(calcMainChainIndexPrefix(bh.Height), binaryBlockHash)
421 clearCacheFuncs = append(clearCacheFuncs, func() {
422 s.cache.removeMainChainHash(bh.Height)
426 if currentStatus != nil {
427 for i := blockHeader.Height + 1; i <= currentStatus.Height; i++ {
429 batch.Delete(calcMainChainIndexPrefix(index))
430 clearCacheFuncs = append(clearCacheFuncs, func() {
431 s.cache.removeMainChainHash(index)
437 for _, clearCacheFunc := range clearCacheFuncs {