github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/database/store_checkpoint.go (about) 1 package database 2 3 import ( 4 "encoding/binary" 5 "encoding/json" 6 "time" 7 8 log "github.com/sirupsen/logrus" 9 10 dbm "github.com/bytom/bytom/database/leveldb" 11 "github.com/bytom/bytom/protocol/bc" 12 "github.com/bytom/bytom/protocol/state" 13 ) 14 15 func calcCheckpointKey(height uint64, hash *bc.Hash) []byte { 16 buf := make([]byte, 8) 17 binary.BigEndian.PutUint64(buf, height) 18 key := append(checkpointKeyPrefix, buf...) 19 if hash != nil { 20 key = append(key, hash.Bytes()...) 21 } 22 return key 23 } 24 25 func getCheckpointFromDB(db dbm.DB, key []byte) (*state.Checkpoint, error) { 26 checkpoint := &state.Checkpoint{} 27 if err := json.Unmarshal(db.Get(key), checkpoint); err != nil { 28 return nil, err 29 } 30 31 return checkpoint, nil 32 } 33 34 func (s *Store) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error) { 35 header, err := s.GetBlockHeader(hash) 36 if err != nil { 37 return nil, err 38 } 39 40 checkpoint, err := s.cache.lookupCheckPoint(calcCheckpointKey(header.Height, hash)) 41 if err != nil { 42 return nil, err 43 } 44 45 checkpoint.SupLinks = append(checkpoint.SupLinks, header.SupLinks...) 46 return checkpoint, nil 47 } 48 49 // GetCheckpointsByHeight return all checkpoints of specified block height 50 func (s *Store) GetCheckpointsByHeight(height uint64) ([]*state.Checkpoint, error) { 51 iter := s.db.IteratorPrefix(calcCheckpointKey(height, nil)) 52 defer iter.Release() 53 return s.loadCheckpointsFromIter(iter) 54 } 55 56 // CheckpointsFromNode return all checkpoints from specified block height and hash 57 func (s *Store) CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error) { 58 startKey := calcCheckpointKey(height, hash) 59 iter := s.db.IteratorPrefixWithStart(checkpointKeyPrefix, startKey, false) 60 61 firstCheckpoint := &state.Checkpoint{} 62 if err := json.Unmarshal(iter.Value(), firstCheckpoint); err != nil { 63 return nil, err 64 } 65 66 checkpoints := []*state.Checkpoint{firstCheckpoint} 67 subs, err := s.loadCheckpointsFromIter(iter) 68 if err != nil { 69 return nil, err 70 } 71 72 checkpoints = append(checkpoints, subs...) 73 return checkpoints, nil 74 } 75 76 func (s *Store) loadCheckpointsFromIter(iter dbm.Iterator) ([]*state.Checkpoint, error) { 77 var checkpoints []*state.Checkpoint 78 defer iter.Release() 79 for iter.Next() { 80 checkpoint := &state.Checkpoint{} 81 if err := json.Unmarshal(iter.Value(), checkpoint); err != nil { 82 return nil, err 83 } 84 85 header, err := s.GetBlockHeader(&checkpoint.Hash) 86 if err != nil { 87 return nil, err 88 } 89 90 checkpoint.SupLinks = append(checkpoint.SupLinks, header.SupLinks...) 91 checkpoints = append(checkpoints, checkpoint) 92 } 93 return checkpoints, nil 94 } 95 96 // SaveCheckpoints bulk save multiple checkpoint 97 func (s *Store) SaveCheckpoints(checkpoints []*state.Checkpoint) error { 98 var keys [][]byte 99 100 batch := s.db.NewBatch() 101 for _, checkpoint := range checkpoints { 102 startTime := time.Now() 103 data, err := json.Marshal(checkpoint) 104 if err != nil { 105 return err 106 } 107 108 key := calcCheckpointKey(checkpoint.Height, &checkpoint.Hash) 109 batch.Set(key, data) 110 keys = append(keys, key) 111 log.WithFields(log.Fields{ 112 "module": logModule, 113 "height": checkpoint.Height, 114 "hash": checkpoint.Hash.String(), 115 "status": checkpoint.Status, 116 "duration": time.Since(startTime), 117 }).Info("checkpoint saved on disk") 118 } 119 120 batch.Write() 121 122 for _, key := range keys { 123 s.cache.removeCheckPoint(key) 124 } 125 126 return nil 127 }