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.

285 lines
6.7 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. dbm "github.com/tendermint/tm-db"
  8. cryptoamino "github.com/tendermint/tendermint/crypto/encoding/amino"
  9. log "github.com/tendermint/tendermint/libs/log"
  10. lerr "github.com/tendermint/tendermint/lite/errors"
  11. "github.com/tendermint/tendermint/types"
  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 "+tmrand.Str(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, err := dbp.db.ReverseIterator(
  91. signedHeaderKey(chainID, minHeight),
  92. append(signedHeaderKey(chainID, maxHeight), byte(0x00)),
  93. )
  94. if err != nil {
  95. panic(err)
  96. }
  97. defer itr.Close()
  98. for itr.Valid() {
  99. key := itr.Key()
  100. _, _, ok := parseSignedHeaderKey(key)
  101. if !ok {
  102. // Skip over other keys.
  103. itr.Next()
  104. continue
  105. } else {
  106. // Found the latest full commit signed header.
  107. shBz := itr.Value()
  108. sh := types.SignedHeader{}
  109. err := dbp.cdc.UnmarshalBinaryLengthPrefixed(shBz, &sh)
  110. if err != nil {
  111. return FullCommit{}, err
  112. }
  113. lfc, err := dbp.fillFullCommit(sh)
  114. if err == nil {
  115. dbp.logger.Info("DBProvider.LatestFullCommit() found latest.", "height", lfc.Height())
  116. return lfc, nil
  117. }
  118. dbp.logger.Error("DBProvider.LatestFullCommit() got error", "lfc", lfc)
  119. dbp.logger.Error(fmt.Sprintf("%+v", err))
  120. return lfc, err
  121. }
  122. }
  123. return FullCommit{}, lerr.ErrCommitNotFound()
  124. }
  125. func (dbp *DBProvider) ValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) {
  126. return dbp.getValidatorSet(chainID, height)
  127. }
  128. func (dbp *DBProvider) getValidatorSet(chainID string, height int64) (valset *types.ValidatorSet, err error) {
  129. vsBz, err := dbp.db.Get(validatorSetKey(chainID, height))
  130. if err != nil {
  131. return nil, err
  132. }
  133. if len(vsBz) == 0 {
  134. err = lerr.ErrUnknownValidators(chainID, height)
  135. return
  136. }
  137. err = dbp.cdc.UnmarshalBinaryLengthPrefixed(vsBz, &valset)
  138. if err != nil {
  139. return
  140. }
  141. // To test deep equality. This makes it easier to test for e.g. valset
  142. // equivalence using assert.Equal (tests for deep equality) in our tests,
  143. // which also tests for unexported/private field equivalence.
  144. valset.TotalVotingPower()
  145. return
  146. }
  147. func (dbp *DBProvider) fillFullCommit(sh types.SignedHeader) (FullCommit, error) {
  148. var chainID = sh.ChainID
  149. var height = sh.Height
  150. var valset, nextValset *types.ValidatorSet
  151. // Load the validator set.
  152. valset, err := dbp.getValidatorSet(chainID, height)
  153. if err != nil {
  154. return FullCommit{}, err
  155. }
  156. // Load the next validator set.
  157. nextValset, err = dbp.getValidatorSet(chainID, height+1)
  158. if err != nil {
  159. return FullCommit{}, err
  160. }
  161. // Return filled FullCommit.
  162. return FullCommit{
  163. SignedHeader: sh,
  164. Validators: valset,
  165. NextValidators: nextValset,
  166. }, nil
  167. }
  168. func (dbp *DBProvider) deleteAfterN(chainID string, after int) error {
  169. dbp.logger.Info("DBProvider.deleteAfterN()...", "chainID", chainID, "after", after)
  170. itr, err := dbp.db.ReverseIterator(
  171. signedHeaderKey(chainID, 1),
  172. append(signedHeaderKey(chainID, 1<<63-1), byte(0x00)),
  173. )
  174. if err != nil {
  175. panic(err)
  176. }
  177. defer itr.Close()
  178. var lastHeight int64 = 1<<63 - 1
  179. var numSeen = 0
  180. var numDeleted = 0
  181. for itr.Valid() {
  182. key := itr.Key()
  183. _, height, ok := parseChainKeyPrefix(key)
  184. if !ok {
  185. return fmt.Errorf("unexpected key %v", key)
  186. }
  187. if height < lastHeight {
  188. lastHeight = height
  189. numSeen++
  190. }
  191. if numSeen > after {
  192. dbp.db.Delete(key)
  193. numDeleted++
  194. }
  195. itr.Next()
  196. }
  197. dbp.logger.Info(fmt.Sprintf("DBProvider.deleteAfterN() deleted %v items", numDeleted))
  198. return nil
  199. }
  200. //----------------------------------------
  201. // key encoding
  202. func signedHeaderKey(chainID string, height int64) []byte {
  203. return []byte(fmt.Sprintf("%s/%010d/sh", chainID, height))
  204. }
  205. func validatorSetKey(chainID string, height int64) []byte {
  206. return []byte(fmt.Sprintf("%s/%010d/vs", chainID, height))
  207. }
  208. //----------------------------------------
  209. // key parsing
  210. var keyPattern = regexp.MustCompile(`^([^/]+)/([0-9]*)/(.*)$`)
  211. func parseKey(key []byte) (chainID string, height int64, part string, ok bool) {
  212. submatch := keyPattern.FindSubmatch(key)
  213. if submatch == nil {
  214. return "", 0, "", false
  215. }
  216. chainID = string(submatch[1])
  217. heightStr := string(submatch[2])
  218. heightInt, err := strconv.Atoi(heightStr)
  219. if err != nil {
  220. return "", 0, "", false
  221. }
  222. height = int64(heightInt)
  223. part = string(submatch[3])
  224. ok = true // good!
  225. return
  226. }
  227. func parseSignedHeaderKey(key []byte) (chainID string, height int64, ok bool) {
  228. var part string
  229. chainID, height, part, ok = parseKey(key)
  230. if part != "sh" {
  231. return "", 0, false
  232. }
  233. return
  234. }
  235. func parseChainKeyPrefix(key []byte) (chainID string, height int64, ok bool) {
  236. chainID, height, _, ok = parseKey(key)
  237. return
  238. }