github.com/evdatsion/aphelion-dpos-bft@v0.32.1/abci/example/kvstore/kvstore.go (about) 1 package kvstore 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "encoding/json" 7 "fmt" 8 9 "github.com/evdatsion/aphelion-dpos-bft/abci/example/code" 10 "github.com/evdatsion/aphelion-dpos-bft/abci/types" 11 cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common" 12 dbm "github.com/evdatsion/aphelion-dpos-bft/libs/db" 13 "github.com/evdatsion/aphelion-dpos-bft/version" 14 ) 15 16 var ( 17 stateKey = []byte("stateKey") 18 kvPairPrefixKey = []byte("kvPairKey:") 19 20 ProtocolVersion version.Protocol = 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 stateBytes := db.Get(stateKey) 32 var state State 33 if len(stateBytes) != 0 { 34 err := json.Unmarshal(stateBytes, &state) 35 if err != nil { 36 panic(err) 37 } 38 } 39 state.db = db 40 return state 41 } 42 43 func saveState(state State) { 44 stateBytes, err := json.Marshal(state) 45 if err != nil { 46 panic(err) 47 } 48 state.db.Set(stateKey, stateBytes) 49 } 50 51 func prefixKey(key []byte) []byte { 52 return append(kvPairPrefixKey, key...) 53 } 54 55 //--------------------------------------------------- 56 57 var _ types.Application = (*KVStoreApplication)(nil) 58 59 type KVStoreApplication struct { 60 types.BaseApplication 61 62 state State 63 } 64 65 func NewKVStoreApplication() *KVStoreApplication { 66 state := loadState(dbm.NewMemDB()) 67 return &KVStoreApplication{state: state} 68 } 69 70 func (app *KVStoreApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { 71 return types.ResponseInfo{ 72 Data: fmt.Sprintf("{\"size\":%v}", app.state.Size), 73 Version: version.ABCIVersion, 74 AppVersion: ProtocolVersion.Uint64(), 75 } 76 } 77 78 // tx is either "key=value" or just arbitrary bytes 79 func (app *KVStoreApplication) DeliverTx(req types.RequestDeliverTx) types.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 := []types.Event{ 92 { 93 Type: "app", 94 Attributes: []cmn.KVPair{ 95 {Key: []byte("creator"), Value: []byte("Cosmoshi Netowoko")}, 96 {Key: []byte("key"), Value: key}, 97 }, 98 }, 99 } 100 101 return types.ResponseDeliverTx{Code: code.CodeTypeOK, Events: events} 102 } 103 104 func (app *KVStoreApplication) CheckTx(req types.RequestCheckTx) types.ResponseCheckTx { 105 return types.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1} 106 } 107 108 func (app *KVStoreApplication) Commit() types.ResponseCommit { 109 // Using a memdb - just return the big endian size of the db 110 appHash := make([]byte, 8) 111 binary.PutVarint(appHash, app.state.Size) 112 app.state.AppHash = appHash 113 app.state.Height += 1 114 saveState(app.state) 115 return types.ResponseCommit{Data: appHash} 116 } 117 118 func (app *KVStoreApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { 119 if reqQuery.Prove { 120 value := app.state.db.Get(prefixKey(reqQuery.Data)) 121 resQuery.Index = -1 // TODO make Proof return index 122 resQuery.Key = reqQuery.Data 123 resQuery.Value = value 124 if value != nil { 125 resQuery.Log = "exists" 126 } else { 127 resQuery.Log = "does not exist" 128 } 129 return 130 } else { 131 resQuery.Key = reqQuery.Data 132 value := app.state.db.Get(prefixKey(reqQuery.Data)) 133 resQuery.Value = value 134 if value != nil { 135 resQuery.Log = "exists" 136 } else { 137 resQuery.Log = "does not exist" 138 } 139 return 140 } 141 }