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