github.com/number571/tendermint@v0.34.11-gost/abci/example/kvstore/kvstore.go (about) 1 package kvstore 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "encoding/json" 7 "fmt" 8 9 dbm "github.com/tendermint/tm-db" 10 11 "github.com/number571/tendermint/abci/example/code" 12 "github.com/number571/tendermint/abci/types" 13 "github.com/number571/tendermint/version" 14 ) 15 16 var ( 17 stateKey = []byte("stateKey") 18 kvPairPrefixKey = []byte("kvPairKey:") 19 20 ProtocolVersion uint64 = 0x1 21 ) 22 23 type State struct { 24 db dbm.DB 25 Size int64 `json:"size"` 26 Height int64 `json:"height"` 27 AppHash []byte `json:"app_hash"` 28 } 29 30 func loadState(db dbm.DB) State { 31 var state State 32 state.db = db 33 stateBytes, err := db.Get(stateKey) 34 if err != nil { 35 panic(err) 36 } 37 if len(stateBytes) == 0 { 38 return state 39 } 40 err = json.Unmarshal(stateBytes, &state) 41 if err != nil { 42 panic(err) 43 } 44 return state 45 } 46 47 func saveState(state State) { 48 stateBytes, err := json.Marshal(state) 49 if err != nil { 50 panic(err) 51 } 52 err = state.db.Set(stateKey, stateBytes) 53 if err != nil { 54 panic(err) 55 } 56 } 57 58 func prefixKey(key []byte) []byte { 59 return append(kvPairPrefixKey, key...) 60 } 61 62 //--------------------------------------------------- 63 64 var _ types.Application = (*Application)(nil) 65 66 type Application struct { 67 types.BaseApplication 68 69 state State 70 RetainBlocks int64 // blocks to retain after commit (via ResponseCommit.RetainHeight) 71 } 72 73 func NewApplication() *Application { 74 state := loadState(dbm.NewMemDB()) 75 return &Application{state: state} 76 } 77 78 func (app *Application) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { 79 return types.ResponseInfo{ 80 Data: fmt.Sprintf("{\"size\":%v}", app.state.Size), 81 Version: version.ABCIVersion, 82 AppVersion: ProtocolVersion, 83 LastBlockHeight: app.state.Height, 84 LastBlockAppHash: app.state.AppHash, 85 } 86 } 87 88 // tx is either "key=value" or just arbitrary bytes 89 func (app *Application) DeliverTx(req types.RequestDeliverTx) types.ResponseDeliverTx { 90 var key, value string 91 92 parts := bytes.Split(req.Tx, []byte("=")) 93 if len(parts) == 2 { 94 key, value = string(parts[0]), string(parts[1]) 95 } else { 96 key, value = string(req.Tx), string(req.Tx) 97 } 98 99 err := app.state.db.Set(prefixKey([]byte(key)), []byte(value)) 100 if err != nil { 101 panic(err) 102 } 103 app.state.Size++ 104 105 events := []types.Event{ 106 { 107 Type: "app", 108 Attributes: []types.EventAttribute{ 109 {Key: "creator", Value: "Cosmoshi Netowoko", Index: true}, 110 {Key: "key", Value: key, Index: true}, 111 {Key: "index_key", Value: "index is working", Index: true}, 112 {Key: "noindex_key", Value: "index is working", Index: false}, 113 }, 114 }, 115 } 116 117 return types.ResponseDeliverTx{Code: code.CodeTypeOK, Events: events} 118 } 119 120 func (app *Application) CheckTx(req types.RequestCheckTx) types.ResponseCheckTx { 121 return types.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1} 122 } 123 124 func (app *Application) Commit() types.ResponseCommit { 125 // Using a memdb - just return the big endian size of the db 126 appHash := make([]byte, 8) 127 binary.PutVarint(appHash, app.state.Size) 128 app.state.AppHash = appHash 129 app.state.Height++ 130 saveState(app.state) 131 132 resp := types.ResponseCommit{Data: appHash} 133 if app.RetainBlocks > 0 && app.state.Height >= app.RetainBlocks { 134 resp.RetainHeight = app.state.Height - app.RetainBlocks + 1 135 } 136 return resp 137 } 138 139 // Returns an associated value or nil if missing. 140 func (app *Application) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { 141 if reqQuery.Prove { 142 value, err := app.state.db.Get(prefixKey(reqQuery.Data)) 143 if err != nil { 144 panic(err) 145 } 146 if value == nil { 147 resQuery.Log = "does not exist" 148 } else { 149 resQuery.Log = "exists" 150 } 151 resQuery.Index = -1 // TODO make Proof return index 152 resQuery.Key = reqQuery.Data 153 resQuery.Value = value 154 resQuery.Height = app.state.Height 155 156 return 157 } 158 159 resQuery.Key = reqQuery.Data 160 value, err := app.state.db.Get(prefixKey(reqQuery.Data)) 161 if err != nil { 162 panic(err) 163 } 164 if value == nil { 165 resQuery.Log = "does not exist" 166 } else { 167 resQuery.Log = "exists" 168 } 169 resQuery.Value = value 170 resQuery.Height = app.state.Height 171 172 return resQuery 173 }