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  }