github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/bft/abci/example/kvstore/kvstore.go (about) 1 package kvstore 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "encoding/json" 7 "fmt" 8 9 abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" 10 abciver "github.com/gnolang/gno/tm2/pkg/bft/abci/version" 11 dbm "github.com/gnolang/gno/tm2/pkg/db" 12 "github.com/gnolang/gno/tm2/pkg/db/memdb" 13 ) 14 15 var ( 16 stateKey = []byte("stateKey") 17 kvPairPrefixKey = []byte("kvPairKey:") 18 AppVersion = "v0.0.0" 19 ) 20 21 type State struct { 22 db dbm.DB 23 Size int64 `json:"size"` 24 Height int64 `json:"height"` 25 AppHash []byte `json:"app_hash"` 26 } 27 28 func loadState(db dbm.DB) State { 29 stateBytes := db.Get(stateKey) 30 var state State 31 if len(stateBytes) != 0 { 32 err := json.Unmarshal(stateBytes, &state) 33 if err != nil { 34 panic(err) 35 } 36 } 37 state.db = db 38 return state 39 } 40 41 func saveState(state State) { 42 stateBytes, err := json.Marshal(state) 43 if err != nil { 44 panic(err) 45 } 46 state.db.Set(stateKey, stateBytes) 47 } 48 49 func prefixKey(key []byte) []byte { 50 return append(kvPairPrefixKey, key...) 51 } 52 53 //--------------------------------------------------- 54 55 var _ abci.Application = (*KVStoreApplication)(nil) 56 57 type KVStoreApplication struct { 58 abci.BaseApplication 59 60 state State 61 } 62 63 func NewKVStoreApplication() *KVStoreApplication { 64 state := loadState(memdb.NewMemDB()) 65 return &KVStoreApplication{state: state} 66 } 67 68 func (app *KVStoreApplication) Info(req abci.RequestInfo) (resInfo abci.ResponseInfo) { 69 return abci.ResponseInfo{ 70 ResponseBase: abci.ResponseBase{ 71 Data: []byte(fmt.Sprintf("{\"size\":%v}", app.state.Size)), 72 }, 73 ABCIVersion: abciver.Version, 74 AppVersion: AppVersion, 75 } 76 } 77 78 // tx is either "key=value" or just arbitrary bytes 79 func (app *KVStoreApplication) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliverTx) { 80 var key, value []byte 81 parts := bytes.Split(req.Tx, []byte("=")) 82 if len(parts) == 2 { 83 key, value = parts[0], parts[1] 84 } else { 85 key, value = req.Tx, req.Tx 86 } 87 88 app.state.db.Set(prefixKey(key), value) 89 app.state.Size += 1 90 91 events := []abci.Event{abci.EventString(`{"creator":"Cosmoshi Netowoko"}`)} 92 93 res.Events = events 94 return res 95 } 96 97 func (app *KVStoreApplication) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx { 98 return abci.ResponseCheckTx{GasWanted: 1} 99 } 100 101 func (app *KVStoreApplication) Commit() (res abci.ResponseCommit) { 102 // Using a memdb - just return the big endian size of the db 103 appHash := make([]byte, 8) 104 binary.PutVarint(appHash, app.state.Size) 105 app.state.AppHash = appHash 106 app.state.Height += 1 107 saveState(app.state) 108 109 res.Data = appHash 110 return res 111 } 112 113 // Returns an associated value or nil if missing. 114 func (app *KVStoreApplication) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQuery) { 115 if reqQuery.Prove { 116 value := app.state.db.Get(prefixKey(reqQuery.Data)) 117 // resQuery.Index = -1 // TODO make Proof return index 118 resQuery.Key = reqQuery.Data 119 resQuery.Value = value 120 if value != nil { 121 resQuery.Log = "exists" 122 } else { 123 resQuery.Log = "does not exist" 124 } 125 return 126 } else { 127 resQuery.Key = reqQuery.Data 128 value := app.state.db.Get(prefixKey(reqQuery.Data)) 129 resQuery.Value = value 130 if value != nil { 131 resQuery.Log = "exists" 132 } else { 133 resQuery.Log = "does not exist" 134 } 135 return 136 } 137 } 138 139 func (app *KVStoreApplication) Close() error { 140 app.state.db.Close() 141 return nil 142 }