OSDN Git Service

get BlockNode from database (#188)
[bytom/vapor.git] / database / store.go
1 package database
2
3 import (
4         "encoding/binary"
5         "encoding/json"
6         "fmt"
7         "time"
8
9         "github.com/golang/protobuf/proto"
10         log "github.com/sirupsen/logrus"
11
12         dbm "github.com/vapor/database/leveldb"
13         "github.com/vapor/database/storage"
14         "github.com/vapor/errors"
15         "github.com/vapor/protocol"
16         "github.com/vapor/protocol/bc"
17         "github.com/vapor/protocol/bc/types"
18         "github.com/vapor/protocol/state"
19 )
20
21 const (
22         // log module
23         logModule = "leveldb"
24         // the byte of colon(:)
25         colon = byte(0x3a)
26 )
27
28 const (
29         blockStore byte = iota
30         blockHashes
31         blockHeader
32         blockTransactons
33         mainChainIndex
34         txStatus
35         voteResult
36 )
37
38 var (
39         blockStoreKey          = []byte{blockStore}
40         blockHashesPrefix      = []byte{blockHashes, colon}
41         blockHeaderPrefix      = []byte{blockHeader, colon}
42         blockTransactonsPrefix = []byte{blockTransactons, colon}
43         mainChainIndexPrefix   = []byte{mainChainIndex, colon}
44         txStatusPrefix         = []byte{txStatus, colon}
45         voteResultPrefix       = []byte{voteResult, colon}
46 )
47
48 func loadBlockStoreStateJSON(db dbm.DB) *protocol.BlockStoreState {
49         bytes := db.Get(blockStoreKey)
50         if bytes == nil {
51                 return nil
52         }
53
54         bsj := &protocol.BlockStoreState{}
55         if err := json.Unmarshal(bytes, bsj); err != nil {
56                 log.WithField("err", err).Panic("fail on unmarshal BlockStoreStateJSON")
57         }
58         return bsj
59 }
60
61 // A Store encapsulates storage for blockchain validation.
62 // It satisfies the interface protocol.Store, and provides additional
63 // methods for querying current data.
64 type Store struct {
65         db    dbm.DB
66         cache cache
67 }
68
69 func calcMainChainIndexPrefix(height uint64) []byte {
70         buf := [8]byte{}
71         binary.BigEndian.PutUint64(buf[:], height)
72         return append(mainChainIndexPrefix, buf[:]...)
73 }
74
75 func calcBlockHashesPrefix(height uint64) []byte {
76         buf := [8]byte{}
77         binary.BigEndian.PutUint64(buf[:], height)
78         return append(blockHashesPrefix, buf[:]...)
79 }
80
81 func calcBlockHeaderKey(hash *bc.Hash) []byte {
82         return append(blockHeaderPrefix, hash.Bytes()...)
83 }
84
85 func calcBlockTransactionsKey(hash *bc.Hash) []byte {
86         return append(blockTransactonsPrefix, hash.Bytes()...)
87 }
88
89 func calcTxStatusKey(hash *bc.Hash) []byte {
90         return append(txStatusPrefix, hash.Bytes()...)
91 }
92
93 func calcVoteResultKey(seq uint64) []byte {
94         buf := [8]byte{}
95         binary.BigEndian.PutUint64(buf[:], seq)
96         return append(voteResultPrefix, buf[:]...)
97 }
98
99 // GetBlockHeader return the block header by given hash
100 func GetBlockHeader(db dbm.DB, hash *bc.Hash) (*types.BlockHeader, error) {
101         binaryBlockHeader := db.Get(calcBlockHeaderKey(hash))
102         if binaryBlockHeader == nil {
103                 return nil, fmt.Errorf("There are no blockHeader with given hash %s", hash.String())
104         }
105
106         blockHeader := &types.BlockHeader{}
107         if err := blockHeader.UnmarshalText(binaryBlockHeader); err != nil {
108                 return nil, err
109         }
110         return blockHeader, nil
111 }
112
113 // GetBlockTransactions return the block transactions by given hash
114 func GetBlockTransactions(db dbm.DB, hash *bc.Hash) ([]*types.Tx, error) {
115         binaryBlockTxs := db.Get(calcBlockTransactionsKey(hash))
116         if binaryBlockTxs == nil {
117                 return nil, fmt.Errorf("There are no block transactions with given hash %s", hash.String())
118         }
119
120         block := &types.Block{}
121         if err := block.UnmarshalText(binaryBlockTxs); err != nil {
122                 return nil, err
123         }
124         return block.Transactions, nil
125 }
126
127 // GetBlockHashesByHeight return block hashes by given height
128 func GetBlockHashesByHeight(db dbm.DB, height uint64) ([]*bc.Hash, error) {
129         binaryHashes := db.Get(calcBlockHashesPrefix(height))
130         if binaryHashes == nil {
131                 return []*bc.Hash{}, nil
132         }
133
134         hashes := []*bc.Hash{}
135         if err := json.Unmarshal(binaryHashes, &hashes); err != nil {
136                 return nil, err
137         }
138         return hashes, nil
139 }
140
141 // GetMainChainHash return BlockHash by given height
142 func GetMainChainHash(db dbm.DB, height uint64) (*bc.Hash, error) {
143         binaryHash := db.Get(calcMainChainIndexPrefix(height))
144         if binaryHash == nil {
145                 return nil, fmt.Errorf("There are no BlockHash with given height %d", height)
146         }
147
148         hash := &bc.Hash{}
149         if err := hash.UnmarshalText(binaryHash); err != nil {
150                 return nil, err
151         }
152         return hash, nil
153 }
154
155 // GetVoteResult return the vote result by given sequence
156 func GetVoteResult(db dbm.DB, seq uint64) (*state.VoteResult, error) {
157         data := db.Get(calcVoteResultKey(seq))
158         if data == nil {
159                 return nil, protocol.ErrNotFoundVoteResult
160         }
161
162         voteResult := new(state.VoteResult)
163         if err := json.Unmarshal(data, voteResult); err != nil {
164                 return nil, errors.Wrap(err, "unmarshaling vote result")
165         }
166         return voteResult, nil
167 }
168
169 // NewStore creates and returns a new Store object.
170 func NewStore(db dbm.DB) *Store {
171         fillBlockHeaderFn := func(hash *bc.Hash) (*types.BlockHeader, error) {
172                 return GetBlockHeader(db, hash)
173         }
174         fillBlockTxsFn := func(hash *bc.Hash) ([]*types.Tx, error) {
175                 return GetBlockTransactions(db, hash)
176         }
177
178         fillBlockHashesFn := func(height uint64) ([]*bc.Hash, error) {
179                 return GetBlockHashesByHeight(db, height)
180         }
181
182         fillMainChainHashFn := func(height uint64) (*bc.Hash, error) {
183                 return GetMainChainHash(db, height)
184         }
185
186         fillVoteResultFn := func(seq uint64) (*state.VoteResult, error) {
187                 return GetVoteResult(db, seq)
188         }
189
190         cache := newCache(fillBlockHeaderFn, fillBlockTxsFn, fillBlockHashesFn, fillMainChainHashFn, fillVoteResultFn)
191         return &Store{
192                 db:    db,
193                 cache: cache,
194         }
195 }
196
197 // BlockExist check if the block is stored in disk
198 func (s *Store) BlockExist(hash *bc.Hash) bool {
199         _, err := s.cache.lookupBlockHeader(hash)
200         return err == nil
201 }
202
203 // GetBlock return the block by given hash
204 func (s *Store) GetBlock(hash *bc.Hash) (*types.Block, error) {
205         blockHeader, err := s.GetBlockHeader(hash)
206         if err != nil {
207                 return nil, err
208         }
209
210         txs, err := s.GetBlockTransactions(hash)
211         if err != nil {
212                 return nil, err
213         }
214
215         return &types.Block{
216                 BlockHeader:  *blockHeader,
217                 Transactions: txs,
218         }, nil
219 }
220
221 // GetBlockHeader return the BlockHeader by given hash
222 func (s *Store) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) {
223         return s.cache.lookupBlockHeader(hash)
224 }
225
226 // GetBlockTransactions return the Block transactions by given hash
227 func (s *Store) GetBlockTransactions(hash *bc.Hash) ([]*types.Tx, error) {
228         return s.cache.lookupBlockTxs(hash)
229 }
230
231 // GetBlockHashesByHeight return the block hash by the specified height
232 func (s *Store) GetBlockHashesByHeight(height uint64) ([]*bc.Hash, error) {
233         return s.cache.lookupBlockHashesByHeight(height)
234 }
235
236 // GetMainChainHash return the block hash by the specified height
237 func (s *Store) GetMainChainHash(height uint64) (*bc.Hash, error) {
238         return s.cache.lookupMainChainHash(height)
239 }
240
241 // GetStoreStatus return the BlockStoreStateJSON
242 func (s *Store) GetStoreStatus() *protocol.BlockStoreState {
243         return loadBlockStoreStateJSON(s.db)
244 }
245
246 // GetTransactionsUtxo will return all the utxo that related to the input txs
247 func (s *Store) GetTransactionsUtxo(view *state.UtxoViewpoint, txs []*bc.Tx) error {
248         return getTransactionsUtxo(s.db, view, txs)
249 }
250
251 // GetTransactionStatus will return the utxo that related to the block hash
252 func (s *Store) GetTransactionStatus(hash *bc.Hash) (*bc.TransactionStatus, error) {
253         data := s.db.Get(calcTxStatusKey(hash))
254         if data == nil {
255                 return nil, errors.New("can't find the transaction status by given hash")
256         }
257
258         ts := &bc.TransactionStatus{}
259         if err := proto.Unmarshal(data, ts); err != nil {
260                 return nil, errors.Wrap(err, "unmarshaling transaction status")
261         }
262         return ts, nil
263 }
264
265 // GetUtxo will search the utxo in db
266 func (s *Store) GetUtxo(hash *bc.Hash) (*storage.UtxoEntry, error) {
267         return getUtxo(s.db, hash)
268 }
269
270 // GetVoteResult retrive the voting result in specified vote sequence
271 func (s *Store) GetVoteResult(seq uint64) (*state.VoteResult, error) {
272         return s.cache.lookupVoteResult(seq)
273 }
274
275 // SaveBlock persists a new block in the protocol.
276 func (s *Store) SaveBlock(block *types.Block, ts *bc.TransactionStatus) error {
277         startTime := time.Now()
278         binaryBlockHeader, err := block.MarshalTextForBlockHeader()
279         if err != nil {
280                 return errors.Wrap(err, "Marshal block header")
281         }
282
283         binaryBlockTxs, err := block.MarshalTextForTransactions()
284         if err != nil {
285                 return errors.Wrap(err, "Marshal block transactions")
286         }
287
288         binaryTxStatus, err := proto.Marshal(ts)
289         if err != nil {
290                 return errors.Wrap(err, "Marshal block transaction status")
291         }
292
293         blockHashes := []*bc.Hash{}
294         hashes, err := s.GetBlockHashesByHeight(block.Height)
295         if err != nil {
296                 return err
297         }
298         blockHashes = append(blockHashes, hashes...)
299         blockHash := block.Hash()
300         blockHashes = append(blockHashes, &blockHash)
301         binaryBlockHashes, err := json.Marshal(blockHashes)
302         if err != nil {
303                 return errors.Wrap(err, "Marshal block hashes")
304         }
305
306         batch := s.db.NewBatch()
307         batch.Set(calcBlockHashesPrefix(block.Height), binaryBlockHashes)
308         batch.Set(calcBlockHeaderKey(&blockHash), binaryBlockHeader)
309         batch.Set(calcBlockTransactionsKey(&blockHash), binaryBlockTxs)
310         batch.Set(calcTxStatusKey(&blockHash), binaryTxStatus)
311         batch.Write()
312
313         s.cache.removeBlockHashes(block.Height)
314         log.WithFields(log.Fields{
315                 "module":   logModule,
316                 "height":   block.Height,
317                 "hash":     blockHash.String(),
318                 "duration": time.Since(startTime),
319         }).Info("block saved on disk")
320         return nil
321 }
322
323 // SaveBlockHeader persists a new block header in the protocol.
324 func (s *Store) SaveBlockHeader(blockHeader *types.BlockHeader) error {
325         binaryBlockHeader, err := blockHeader.MarshalText()
326         if err != nil {
327                 return errors.Wrap(err, "Marshal block header")
328         }
329
330         blockHash := blockHeader.Hash()
331         s.db.Set(calcBlockHeaderKey(&blockHash), binaryBlockHeader)
332         s.cache.removeBlockHeader(blockHeader)
333         return nil
334 }
335
336 // SaveChainStatus save the core's newest status && delete old status
337 func (s *Store) SaveChainStatus(blockHeader, irrBlockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, voteResults []*state.VoteResult) error {
338         batch := s.db.NewBatch()
339         if err := saveUtxoView(batch, view); err != nil {
340                 return err
341         }
342
343         for _, vote := range voteResults {
344                 bytes, err := json.Marshal(vote)
345                 if err != nil {
346                         return err
347                 }
348
349                 batch.Set(calcVoteResultKey(vote.Seq), bytes)
350                 s.cache.removeVoteResult(vote)
351         }
352
353         blockHash := blockHeader.Hash()
354         irrBlockHash := irrBlockHeader.Hash()
355         bytes, err := json.Marshal(protocol.BlockStoreState{
356                 Height:             blockHeader.Height,
357                 Hash:               &blockHash,
358                 IrreversibleHeight: irrBlockHeader.Height,
359                 IrreversibleHash:   &irrBlockHash,
360         })
361         if err != nil {
362                 return err
363         }
364         batch.Set(blockStoreKey, bytes)
365
366         // save main chain blockHeaders
367         for _, bh := range mainBlockHeaders {
368                 blockHash := bh.Hash()
369                 binaryBlockHash, err := blockHash.MarshalText()
370                 if err != nil {
371                         return errors.Wrap(err, "Marshal block hash")
372                 }
373
374                 batch.Set(calcMainChainIndexPrefix(bh.Height), binaryBlockHash)
375                 s.cache.removeMainChainHash(bh.Height)
376         }
377         batch.Write()
378         return nil
379 }