package db import ( "errors" "fmt" "regexp" "strconv" "github.com/tendermint/go-amino" dbm "github.com/tendermint/tm-db" cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/tendermint/tendermint/lite2/store" "github.com/tendermint/tendermint/types" ) type dbs struct { db dbm.DB prefix string cdc *amino.Codec } // New returns a Store that wraps any DB (with an optional prefix in case you // want to use one DB with many light clients). func New(db dbm.DB, prefix string) store.Store { cdc := amino.NewCodec() cryptoAmino.RegisterAmino(cdc) return &dbs{db: db, prefix: prefix, cdc: cdc} } func (s *dbs) SaveSignedHeader(sh *types.SignedHeader) error { if sh.Height <= 0 { panic("negative or zero height") } bz, err := s.cdc.MarshalBinaryLengthPrefixed(sh) if err != nil { return err } s.db.Set(s.shKey(sh.Height), bz) return nil } func (s *dbs) SaveValidatorSet(valSet *types.ValidatorSet, height int64) error { if height <= 0 { panic("negative or zero height") } bz, err := s.cdc.MarshalBinaryLengthPrefixed(valSet) if err != nil { return err } s.db.Set(s.vsKey(height), bz) return nil } func (s *dbs) SignedHeader(height int64) (*types.SignedHeader, error) { bz := s.db.Get(s.shKey(height)) if bz == nil { return nil, nil } var signedHeader *types.SignedHeader err := s.cdc.UnmarshalBinaryLengthPrefixed(bz, &signedHeader) return signedHeader, err } func (s *dbs) ValidatorSet(height int64) (*types.ValidatorSet, error) { bz := s.db.Get(s.vsKey(height)) if bz == nil { return nil, nil } var valSet *types.ValidatorSet err := s.cdc.UnmarshalBinaryLengthPrefixed(bz, &valSet) return valSet, err } func (s *dbs) LastSignedHeaderHeight() (int64, error) { itr := s.db.ReverseIterator( s.shKey(1), append(s.shKey(1<<63-1), byte(0x00)), ) defer itr.Close() for itr.Valid() { key := itr.Key() _, height, ok := parseShKey(key) if ok { return height, nil } } return -1, errors.New("no headers found") } func (s *dbs) shKey(height int64) []byte { return []byte(fmt.Sprintf("sh/%s/%010d", s.prefix, height)) } func (s *dbs) vsKey(height int64) []byte { return []byte(fmt.Sprintf("vs/%s/%010d", s.prefix, height)) } var keyPattern = regexp.MustCompile(`^(sh|vs)/([^/]*)/([0-9]+)/$`) func parseKey(key []byte) (part string, prefix string, height int64, ok bool) { submatch := keyPattern.FindSubmatch(key) if submatch == nil { return "", "", 0, false } part = string(submatch[1]) prefix = string(submatch[2]) heightStr := string(submatch[3]) heightInt, err := strconv.Atoi(heightStr) if err != nil { return "", "", 0, false } height = int64(heightInt) ok = true // good! return } func parseShKey(key []byte) (prefix string, height int64, ok bool) { var part string part, prefix, height, ok = parseKey(key) if part != "sh" { return "", 0, false } return }