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