You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

275 lines
6.6 KiB

lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
  1. package lite
  2. import (
  3. "fmt"
  4. "regexp"
  5. "strconv"
  6. amino "github.com/tendermint/go-amino"
  7. cryptoamino "github.com/tendermint/tendermint/crypto/encoding/amino"
  8. log "github.com/tendermint/tendermint/libs/log"
  9. lerr "github.com/tendermint/tendermint/lite/errors"
  10. "github.com/tendermint/tendermint/types"
  11. dbm "github.com/tendermint/tm-db"
  12. )
  13. var _ PersistentProvider = (*DBProvider)(nil)
  14. // DBProvider stores commits and validator sets in a DB.
  15. type DBProvider struct {
  16. logger log.Logger
  17. label string
  18. db dbm.DB
  19. cdc *amino.Codec
  20. limit int
  21. }
  22. func NewDBProvider(label string, db dbm.DB) *DBProvider {
  23. // NOTE: when debugging, this type of construction might be useful.
  24. //db = dbm.NewDebugDB("db provider "+rand.RandStr(4), db)
  25. cdc := amino.NewCodec()
  26. cryptoamino.RegisterAmino(cdc)
  27. dbp := &DBProvider{
  28. logger: log.NewNopLogger(),
  29. label: label,
  30. db: db,
  31. cdc: cdc,
  32. }
  33. return dbp
  34. }
  35. func (dbp *DBProvider) SetLogger(logger log.Logger) {
  36. dbp.logger = logger.With("label", dbp.label)
  37. }
  38. func (dbp *DBProvider) SetLimit(limit int) *DBProvider {
  39. dbp.limit = limit
  40. return dbp
  41. }
  42. // Implements PersistentProvider.
  43. func (dbp *DBProvider) SaveFullCommit(fc FullCommit) error {
  44. dbp.logger.Info("DBProvider.SaveFullCommit()...", "fc", fc)
  45. batch := dbp.db.NewBatch()
  46. defer batch.Close()
  47. // Save the fc.validators.
  48. // We might be overwriting what we already have, but
  49. // it makes the logic easier for now.
  50. vsKey := validatorSetKey(fc.ChainID(), fc.Height())
  51. vsBz, err := dbp.cdc.MarshalBinaryLengthPrefixed(fc.Validators)
  52. if err != nil {
  53. return err
  54. }
  55. batch.Set(vsKey, vsBz)
  56. // Save the fc.NextValidators.
  57. nvsKey := validatorSetKey(fc.ChainID(), fc.Height()+1)
  58. nvsBz, err := dbp.cdc.MarshalBinaryLengthPrefixed(fc.NextValidators)
  59. if err != nil {
  60. return err
  61. }
  62. batch.Set(nvsKey, nvsBz)
  63. // Save the fc.SignedHeader
  64. shKey := signedHeaderKey(fc.ChainID(), fc.Height())
  65. shBz, err := dbp.cdc.MarshalBinaryLengthPrefixed(fc.SignedHeader)
  66. if err != nil {
  67. return err
  68. }
  69. batch.Set(shKey, shBz)
  70. // And write sync.
  71. batch.WriteSync()
  72. // Garbage collect.
  73. // TODO: optimize later.
  74. if dbp.limit > 0 {
  75. dbp.deleteAfterN(fc.ChainID(), dbp.limit)
  76. }
  77. return nil
  78. }
  79. // Implements Provider.
  80. func (dbp *DBProvider) LatestFullCommit(chainID string, minHeight, maxHeight int64) (
  81. FullCommit, error) {
  82. dbp.logger.Info("DBProvider.LatestFullCommit()...",
  83. "chainID", chainID, "minHeight", minHeight, "maxHeight", maxHeight)
  84. if minHeight <= 0 {
  85. minHeight = 1
  86. }
  87. if maxHeight == 0 {
  88. maxHeight = 1<<63 - 1
  89. }
  90. itr := dbp.db.ReverseIterator(
  91. signedHeaderKey(chainID, minHeight),
  92. append(signedHeaderKey(chainID, maxHeight), byte(0x00)),
  93. )
  94. defer itr.Close()
  95. for itr.Valid() {
  96. key := itr.Key()
  97. _, _, ok := parseSignedHeaderKey(key)
  98. if !ok {
  99. // Skip over other keys.
  100. itr.Next()
  101. continue
  102. } else {
  103. // Found the latest full commit signed header.
  104. shBz := itr.Value()
  105. sh := types.SignedHeader{}
  106. err := dbp.cdc.UnmarshalBinaryLengthPrefixed(shBz, &sh)
  107. if err != nil {
  108. return FullCommit{}, err
  109. }
  110. lfc, err := dbp.fillFullCommit(sh)
  111. if err == nil {
  112. dbp.logger.Info("DBProvider.LatestFullCommit() found latest.", "height", lfc.Height())
  113. return lfc, nil
  114. }
  115. dbp.logger.Error("DBProvider.LatestFullCommit() got error", "lfc", lfc)
  116. dbp.logger.Error(fmt.Sprintf("%+v", err))
  117. return lfc, err
  118. }
  119. }
  120. return FullCommit{}, lerr.ErrCommitNotFound()
  121. }
  122. func (dbp *DBProvider) ValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) {
  123. return dbp.getValidatorSet(chainID, height)
  124. }
  125. func (dbp *DBProvider) getValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) {
  126. vsBz := dbp.db.Get(validatorSetKey(chainID, height))
  127. if vsBz == nil {
  128. err = lerr.ErrUnknownValidators(chainID, height)
  129. return
  130. }
  131. err = dbp.cdc.UnmarshalBinaryLengthPrefixed(vsBz, &valset)
  132. if err != nil {
  133. return
  134. }
  135. // To test deep equality. This makes it easier to test for e.g. valset
  136. // equivalence using assert.Equal (tests for deep equality) in our tests,
  137. // which also tests for unexported/private field equivalence.
  138. valset.TotalVotingPower()
  139. return
  140. }
  141. func (dbp *DBProvider) fillFullCommit(sh types.SignedHeader) (FullCommit, error) {
  142. var chainID = sh.ChainID
  143. var height = sh.Height
  144. var valset, nextValset *types.ValidatorSet
  145. // Load the validator set.
  146. valset, err := dbp.getValidatorSet(chainID, height)
  147. if err != nil {
  148. return FullCommit{}, err
  149. }
  150. // Load the next validator set.
  151. nextValset, err = dbp.getValidatorSet(chainID, height+1)
  152. if err != nil {
  153. return FullCommit{}, err
  154. }
  155. // Return filled FullCommit.
  156. return FullCommit{
  157. SignedHeader: sh,
  158. Validators: valset,
  159. NextValidators: nextValset,
  160. }, nil
  161. }
  162. func (dbp *DBProvider) deleteAfterN(chainID string, after int) error {
  163. dbp.logger.Info("DBProvider.deleteAfterN()...", "chainID", chainID, "after", after)
  164. itr := dbp.db.ReverseIterator(
  165. signedHeaderKey(chainID, 1),
  166. append(signedHeaderKey(chainID, 1<<63-1), byte(0x00)),
  167. )
  168. defer itr.Close()
  169. var lastHeight int64 = 1<<63 - 1
  170. var numSeen = 0
  171. var numDeleted = 0
  172. for itr.Valid() {
  173. key := itr.Key()
  174. _, height, ok := parseChainKeyPrefix(key)
  175. if !ok {
  176. return fmt.Errorf("unexpected key %v", key)
  177. }
  178. if height < lastHeight {
  179. lastHeight = height
  180. numSeen++
  181. }
  182. if numSeen > after {
  183. dbp.db.Delete(key)
  184. numDeleted++
  185. }
  186. itr.Next()
  187. }
  188. dbp.logger.Info(fmt.Sprintf("DBProvider.deleteAfterN() deleted %v items", numDeleted))
  189. return nil
  190. }
  191. //----------------------------------------
  192. // key encoding
  193. func signedHeaderKey(chainID string, height int64) []byte {
  194. return []byte(fmt.Sprintf("%s/%010d/sh", chainID, height))
  195. }
  196. func validatorSetKey(chainID string, height int64) []byte {
  197. return []byte(fmt.Sprintf("%s/%010d/vs", chainID, height))
  198. }
  199. //----------------------------------------
  200. // key parsing
  201. var keyPattern = regexp.MustCompile(`^([^/]+)/([0-9]*)/(.*)$`)
  202. func parseKey(key []byte) (chainID string, height int64, part string, ok bool) {
  203. submatch := keyPattern.FindSubmatch(key)
  204. if submatch == nil {
  205. return "", 0, "", false
  206. }
  207. chainID = string(submatch[1])
  208. heightStr := string(submatch[2])
  209. heightInt, err := strconv.Atoi(heightStr)
  210. if err != nil {
  211. return "", 0, "", false
  212. }
  213. height = int64(heightInt)
  214. part = string(submatch[3])
  215. ok = true // good!
  216. return
  217. }
  218. func parseSignedHeaderKey(key []byte) (chainID string, height int64, ok bool) {
  219. var part string
  220. chainID, height, part, ok = parseKey(key)
  221. if part != "sh" {
  222. return "", 0, false
  223. }
  224. return
  225. }
  226. func parseChainKeyPrefix(key []byte) (chainID string, height int64, ok bool) {
  227. chainID, height, _, ok = parseKey(key)
  228. return
  229. }