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.

134 lines
3.2 KiB

9 years ago
9 years ago
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. package kvstore
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "encoding/json"
  6. "fmt"
  7. "github.com/tendermint/tendermint/abci/example/code"
  8. "github.com/tendermint/tendermint/abci/types"
  9. cmn "github.com/tendermint/tendermint/libs/common"
  10. dbm "github.com/tendermint/tendermint/libs/db"
  11. "github.com/tendermint/tendermint/version"
  12. )
  13. var (
  14. stateKey = []byte("stateKey")
  15. kvPairPrefixKey = []byte("kvPairKey:")
  16. ProtocolVersion version.Protocol = 0x1
  17. )
  18. type State struct {
  19. db dbm.DB
  20. Size int64 `json:"size"`
  21. Height int64 `json:"height"`
  22. AppHash []byte `json:"app_hash"`
  23. }
  24. func loadState(db dbm.DB) State {
  25. stateBytes := db.Get(stateKey)
  26. var state State
  27. if len(stateBytes) != 0 {
  28. err := json.Unmarshal(stateBytes, &state)
  29. if err != nil {
  30. panic(err)
  31. }
  32. }
  33. state.db = db
  34. return state
  35. }
  36. func saveState(state State) {
  37. stateBytes, err := json.Marshal(state)
  38. if err != nil {
  39. panic(err)
  40. }
  41. state.db.Set(stateKey, stateBytes)
  42. }
  43. func prefixKey(key []byte) []byte {
  44. return append(kvPairPrefixKey, key...)
  45. }
  46. //---------------------------------------------------
  47. var _ types.Application = (*KVStoreApplication)(nil)
  48. type KVStoreApplication struct {
  49. types.BaseApplication
  50. state State
  51. }
  52. func NewKVStoreApplication() *KVStoreApplication {
  53. state := loadState(dbm.NewMemDB())
  54. return &KVStoreApplication{state: state}
  55. }
  56. func (app *KVStoreApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
  57. return types.ResponseInfo{
  58. Data: fmt.Sprintf("{\"size\":%v}", app.state.Size),
  59. Version: version.ABCIVersion,
  60. AppVersion: ProtocolVersion.Uint64(),
  61. }
  62. }
  63. // tx is either "key=value" or just arbitrary bytes
  64. func (app *KVStoreApplication) DeliverTx(tx []byte) types.ResponseDeliverTx {
  65. var key, value []byte
  66. parts := bytes.Split(tx, []byte("="))
  67. if len(parts) == 2 {
  68. key, value = parts[0], parts[1]
  69. } else {
  70. key, value = tx, tx
  71. }
  72. app.state.db.Set(prefixKey(key), value)
  73. app.state.Size += 1
  74. tags := []cmn.KVPair{
  75. {Key: []byte("app.creator"), Value: []byte("Cosmoshi Netowoko")},
  76. {Key: []byte("app.key"), Value: key},
  77. }
  78. return types.ResponseDeliverTx{Code: code.CodeTypeOK, Tags: tags}
  79. }
  80. func (app *KVStoreApplication) CheckTx(tx []byte) types.ResponseCheckTx {
  81. return types.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1}
  82. }
  83. func (app *KVStoreApplication) Commit() types.ResponseCommit {
  84. // Using a memdb - just return the big endian size of the db
  85. appHash := make([]byte, 8)
  86. binary.PutVarint(appHash, app.state.Size)
  87. app.state.AppHash = appHash
  88. app.state.Height += 1
  89. saveState(app.state)
  90. return types.ResponseCommit{Data: appHash}
  91. }
  92. func (app *KVStoreApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
  93. if reqQuery.Prove {
  94. value := app.state.db.Get(prefixKey(reqQuery.Data))
  95. resQuery.Index = -1 // TODO make Proof return index
  96. resQuery.Key = reqQuery.Data
  97. resQuery.Value = value
  98. if value != nil {
  99. resQuery.Log = "exists"
  100. } else {
  101. resQuery.Log = "does not exist"
  102. }
  103. return
  104. } else {
  105. resQuery.Key = reqQuery.Data
  106. value := app.state.db.Get(prefixKey(reqQuery.Data))
  107. resQuery.Value = value
  108. if value != nil {
  109. resQuery.Log = "exists"
  110. } else {
  111. resQuery.Log = "does not exist"
  112. }
  113. return
  114. }
  115. }