cosmos-sdk/app/app.go

215 lines
5.4 KiB
Go
Raw Normal View History

package app
2016-02-05 23:16:33 -08:00
import (
"strings"
2017-01-14 20:42:47 -08:00
abci "github.com/tendermint/abci/types"
2017-07-03 08:32:01 -07:00
"github.com/tendermint/basecoin"
2016-02-05 23:16:33 -08:00
eyes "github.com/tendermint/merkleeyes/client"
2017-06-21 09:15:11 -07:00
cmn "github.com/tendermint/tmlibs/common"
2017-05-01 07:03:54 -07:00
"github.com/tendermint/tmlibs/log"
2017-07-03 08:32:01 -07:00
"github.com/tendermint/basecoin/errors"
"github.com/tendermint/basecoin/modules/coin"
"github.com/tendermint/basecoin/stack"
sm "github.com/tendermint/basecoin/state"
"github.com/tendermint/basecoin/version"
2016-02-05 23:16:33 -08:00
)
2016-03-27 12:47:50 -07:00
const (
2016-04-18 08:09:19 -07:00
PluginNameBase = "base"
2016-03-27 12:47:50 -07:00
)
2016-02-05 23:16:33 -08:00
2016-02-16 12:29:54 -08:00
type Basecoin struct {
2016-05-01 13:52:08 -07:00
eyesCli *eyes.Client
state *sm.State
cacheState *sm.State
2017-07-03 08:32:01 -07:00
handler basecoin.Handler
2017-05-01 07:03:54 -07:00
logger log.Logger
2016-02-05 23:16:33 -08:00
}
2017-07-03 08:32:01 -07:00
func NewBasecoin(h basecoin.Handler, eyesCli *eyes.Client, l log.Logger) *Basecoin {
state := sm.NewState(eyesCli, l.With("module", "state"))
2016-02-16 12:29:54 -08:00
return &Basecoin{
2017-07-03 08:32:01 -07:00
handler: h,
2016-05-01 13:52:08 -07:00
eyesCli: eyesCli,
state: state,
cacheState: nil,
logger: l,
2016-02-05 23:16:33 -08:00
}
}
2017-07-03 08:32:01 -07:00
// placeholder to just handle sendtx
func DefaultHandler() basecoin.Handler {
// use the default stack
h := coin.NewHandler()
return stack.NewDefault().Use(h)
}
// XXX For testing, not thread safe!
2017-02-03 13:06:12 -08:00
func (app *Basecoin) GetState() *sm.State {
return app.state.CacheWrap()
}
// ABCI::Info
2017-01-14 20:42:47 -08:00
func (app *Basecoin) Info() abci.ResponseInfo {
2017-06-21 09:15:11 -07:00
resp, err := app.eyesCli.InfoSync()
if err != nil {
cmn.PanicCrisis(err)
}
return abci.ResponseInfo{
Data: cmn.Fmt("Basecoin v%v", version.Version),
LastBlockHeight: resp.LastBlockHeight,
LastBlockAppHash: resp.LastBlockAppHash,
}
2016-02-05 23:16:33 -08:00
}
// ABCI::SetOption
2017-02-13 14:04:49 -08:00
func (app *Basecoin) SetOption(key string, value string) string {
2017-07-03 08:32:01 -07:00
// TODO
return "todo"
// pluginName, key := splitKey(key)
// if pluginName != PluginNameBase {
// // Set option on plugin
// plugin := app.plugins.GetByName(pluginName)
// if plugin == nil {
// return "Invalid plugin name: " + pluginName
// }
// app.logger.Info("SetOption on plugin", "plugin", pluginName, "key", key, "value", value)
// return plugin.SetOption(app.state, key, value)
// } else {
// // Set option on basecoin
// switch key {
// case "chain_id":
// app.state.SetChainID(value)
// return "Success"
// case "account":
// var acc GenesisAccount
// err := json.Unmarshal([]byte(value), &acc)
// if err != nil {
// return "Error decoding acc message: " + err.Error()
// }
// acc.Balance.Sort()
// addr, err := acc.GetAddr()
// if err != nil {
// return "Invalid address: " + err.Error()
// }
// app.state.SetAccount(addr, acc.ToAccount())
// app.logger.Info("SetAccount", "addr", hex.EncodeToString(addr), "acc", acc)
// return "Success"
// }
// return "Unrecognized option key " + key
// }
2016-02-05 23:16:33 -08:00
}
// ABCI::DeliverTx
2017-07-03 08:32:01 -07:00
func (app *Basecoin) DeliverTx(txBytes []byte) abci.Result {
tx, err := basecoin.LoadTx(txBytes)
2016-02-05 23:16:33 -08:00
if err != nil {
2017-07-03 08:32:01 -07:00
return errors.Result(err)
2016-02-05 23:16:33 -08:00
}
2017-01-12 12:25:04 -08:00
2017-07-03 08:32:01 -07:00
// TODO: can we abstract this setup and commit logic??
cache := app.state.CacheWrap()
ctx := stack.NewContext(app.state.GetChainID(),
app.logger.With("call", "delivertx"))
res, err := app.handler.DeliverTx(ctx, cache, tx)
if err != nil {
// discard the cache...
return errors.Result(err)
2016-02-05 23:16:33 -08:00
}
2017-07-03 08:32:01 -07:00
// commit the cache and return result
cache.CacheSync()
return res.ToABCI()
2016-02-05 23:16:33 -08:00
}
// ABCI::CheckTx
2017-07-03 08:32:01 -07:00
func (app *Basecoin) CheckTx(txBytes []byte) abci.Result {
tx, err := basecoin.LoadTx(txBytes)
2016-02-05 23:16:33 -08:00
if err != nil {
2017-07-03 08:32:01 -07:00
return errors.Result(err)
2016-02-05 23:16:33 -08:00
}
2017-01-12 12:25:04 -08:00
2017-07-03 08:32:01 -07:00
// TODO: can we abstract this setup and commit logic??
ctx := stack.NewContext(app.state.GetChainID(),
app.logger.With("call", "checktx"))
// checktx generally shouldn't touch the state, but we don't care
// here on the framework level, since the cacheState is thrown away next block
res, err := app.handler.CheckTx(ctx, app.cacheState, tx)
if err != nil {
return errors.Result(err)
2016-02-05 23:16:33 -08:00
}
2017-07-03 08:32:01 -07:00
return res.ToABCI()
2016-02-05 23:16:33 -08:00
}
// ABCI::Query
2017-01-28 09:29:32 -08:00
func (app *Basecoin) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQuery) {
if len(reqQuery.Data) == 0 {
resQuery.Log = "Query cannot be zero length"
resQuery.Code = abci.CodeType_EncodingError
return
2016-03-27 21:51:04 -07:00
}
2017-01-12 12:25:04 -08:00
2017-01-28 09:29:32 -08:00
resQuery, err := app.eyesCli.QuerySync(reqQuery)
if err != nil {
resQuery.Log = "Failed to query MerkleEyes: " + err.Error()
resQuery.Code = abci.CodeType_InternalError
return
}
return
2016-02-05 23:16:33 -08:00
}
// ABCI::Commit
2017-01-14 20:42:47 -08:00
func (app *Basecoin) Commit() (res abci.Result) {
2017-01-12 17:49:51 -08:00
// Commit state
res = app.state.Commit()
2017-01-12 12:25:04 -08:00
// Wrap the committed state in cache for CheckTx
app.cacheState = app.state.CacheWrap()
if res.IsErr() {
2017-06-21 09:15:11 -07:00
cmn.PanicSanity("Error getting hash: " + res.Error())
2016-02-05 23:16:33 -08:00
}
return res
2016-02-05 23:16:33 -08:00
}
// ABCI::InitChain
2017-01-14 20:42:47 -08:00
func (app *Basecoin) InitChain(validators []*abci.Validator) {
2017-07-03 08:32:01 -07:00
// for _, plugin := range app.plugins.GetList() {
// plugin.InitChain(app.state, validators)
// }
2016-03-15 15:01:53 -07:00
}
// ABCI::BeginBlock
func (app *Basecoin) BeginBlock(hash []byte, header *abci.Header) {
2017-07-03 08:32:01 -07:00
// for _, plugin := range app.plugins.GetList() {
// plugin.BeginBlock(app.state, hash, header)
// }
2016-03-29 14:25:17 -07:00
}
// ABCI::EndBlock
func (app *Basecoin) EndBlock(height uint64) (res abci.ResponseEndBlock) {
2017-07-03 08:32:01 -07:00
// for _, plugin := range app.plugins.GetList() {
// pluginRes := plugin.EndBlock(app.state, height)
// res.Diffs = append(res.Diffs, pluginRes.Diffs...)
// }
2016-04-18 08:09:19 -07:00
return
2016-03-15 15:01:53 -07:00
}
//----------------------------------------
2016-04-17 12:41:26 -07:00
// Splits the string at the first '/'.
// if there are none, the second string is nil.
2016-04-17 12:41:26 -07:00
func splitKey(key string) (prefix string, suffix string) {
2016-03-27 12:47:50 -07:00
if strings.Contains(key, "/") {
keyParts := strings.SplitN(key, "/", 2)
return keyParts[0], keyParts[1]
}
return key, ""
}