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  }