cosmos-sdk/app/app.go

178 lines
4.1 KiB
Go

package app
import (
"strings"
abci "github.com/tendermint/abci/types"
sm "github.com/tendermint/basecoin/state"
"github.com/tendermint/basecoin/types"
. "github.com/tendermint/go-common"
"github.com/tendermint/go-wire"
eyes "github.com/tendermint/merkleeyes/client"
)
const (
version = "0.1"
maxTxSize = 10240
PluginNameBase = "base"
)
type Basecoin struct {
eyesCli *eyes.Client
state *sm.State
cacheState *sm.State
plugins *types.Plugins
}
func NewBasecoin(eyesCli *eyes.Client) *Basecoin {
state := sm.NewState(eyesCli)
plugins := types.NewPlugins()
return &Basecoin{
eyesCli: eyesCli,
state: state,
cacheState: nil,
plugins: plugins,
}
}
// TMSP::Info
func (app *Basecoin) Info() abci.ResponseInfo {
return abci.ResponseInfo{Data: Fmt("Basecoin v%v", version)}
}
func (app *Basecoin) RegisterPlugin(name string, plugin types.Plugin) {
app.plugins.RegisterPlugin(name, plugin)
}
// TMSP::SetOption
func (app *Basecoin) SetOption(key string, value string) (log string) {
PluginName, key := splitKey(key)
if PluginName != PluginNameBase {
// Set option on plugin
plugin := app.plugins.GetByName(PluginName)
if plugin == nil {
return "Invalid plugin name: " + PluginName
}
return plugin.SetOption(app.state, key, value)
} else {
// Set option on basecoin
switch key {
case "chainID":
app.state.SetChainID(value)
return "Success"
case "account":
var err error
var acc *types.Account
wire.ReadJSONPtr(&acc, []byte(value), &err)
if err != nil {
return "Error decoding acc message: " + err.Error()
}
app.state.SetAccount(acc.PubKey.Address(), acc)
return "Success"
}
return "Unrecognized option key " + key
}
}
// TMSP::DeliverTx
func (app *Basecoin) DeliverTx(txBytes []byte) (res abci.Result) {
if len(txBytes) > maxTxSize {
return abci.ErrBaseEncodingError.AppendLog("Tx size exceeds maximum")
}
// Decode tx
var tx types.Tx
err := wire.ReadBinaryBytes(txBytes, &tx)
if err != nil {
return abci.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error())
}
// Validate and exec tx
res = sm.ExecTx(app.state, app.plugins, tx, false, nil)
if res.IsErr() {
return res.PrependLog("Error in DeliverTx")
}
return abci.OK
}
// TMSP::CheckTx
func (app *Basecoin) CheckTx(txBytes []byte) (res abci.Result) {
if len(txBytes) > maxTxSize {
return abci.ErrBaseEncodingError.AppendLog("Tx size exceeds maximum")
}
// Decode tx
var tx types.Tx
err := wire.ReadBinaryBytes(txBytes, &tx)
if err != nil {
return abci.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error())
}
// Validate tx
res = sm.ExecTx(app.cacheState, app.plugins, tx, true, nil)
if res.IsErr() {
return res.PrependLog("Error in CheckTx")
}
return abci.OK
}
// TMSP::Query
func (app *Basecoin) Query(query []byte) (res abci.Result) {
if len(query) == 0 {
return abci.ErrEncodingError.SetLog("Query cannot be zero length")
}
return app.eyesCli.QuerySync(query)
}
// TMSP::Commit
func (app *Basecoin) Commit() (res abci.Result) {
// Commit state
res = app.state.Commit()
// Wrap the committed state in cache for CheckTx
app.cacheState = app.state.CacheWrap()
if res.IsErr() {
PanicSanity("Error getting hash: " + res.Error())
}
return res
}
// TMSP::InitChain
func (app *Basecoin) InitChain(validators []*abci.Validator) {
for _, plugin := range app.plugins.GetList() {
plugin.Plugin.InitChain(app.state, validators)
}
}
// TMSP::BeginBlock
func (app *Basecoin) BeginBlock(height uint64) {
for _, plugin := range app.plugins.GetList() {
plugin.Plugin.BeginBlock(app.state, height)
}
}
// TMSP::EndBlock
func (app *Basecoin) EndBlock(height uint64) (diffs []*abci.Validator) {
for _, plugin := range app.plugins.GetList() {
moreDiffs := plugin.Plugin.EndBlock(app.state, height)
diffs = append(diffs, moreDiffs...)
}
return
}
//----------------------------------------
// Splits the string at the first '/'.
// if there are none, the second string is nil.
func splitKey(key string) (prefix string, suffix string) {
if strings.Contains(key, "/") {
keyParts := strings.SplitN(key, "/", 2)
return keyParts[0], keyParts[1]
}
return key, ""
}