179 lines
4.3 KiB
Go
179 lines
4.3 KiB
Go
package app
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/tendermint/basecoin/state"
|
|
"github.com/tendermint/basecoin/types"
|
|
. "github.com/tendermint/go-common"
|
|
"github.com/tendermint/go-wire"
|
|
"github.com/tendermint/governmint/gov"
|
|
eyes "github.com/tendermint/merkleeyes/client"
|
|
tmsp "github.com/tendermint/tmsp/types"
|
|
)
|
|
|
|
const (
|
|
version = "0.1"
|
|
maxTxSize = 10240
|
|
|
|
typeByteBase = 0x01
|
|
typeByteEyes = 0x02
|
|
typeByteGov = 0x03
|
|
|
|
pluginNameBase = "base"
|
|
pluginNameEyes = "eyes"
|
|
pluginNameGov = "gov"
|
|
)
|
|
|
|
type Basecoin struct {
|
|
eyesCli *eyes.Client
|
|
govMint *gov.Governmint
|
|
state *state.State
|
|
plugins *types.Plugins
|
|
}
|
|
|
|
func NewBasecoin(eyesCli *eyes.Client) *Basecoin {
|
|
govMint := gov.NewGovernmint(eyesCli)
|
|
state_ := state.NewState(eyesCli)
|
|
plugins := types.NewPlugins()
|
|
plugins.RegisterPlugin(typeByteGov, pluginNameGov, govMint) // TODO: make constants
|
|
return &Basecoin{
|
|
eyesCli: eyesCli,
|
|
govMint: govMint,
|
|
state: state_,
|
|
plugins: plugins,
|
|
}
|
|
}
|
|
|
|
// TMSP::Info
|
|
func (app *Basecoin) Info() string {
|
|
return Fmt("Basecoin v%v", version)
|
|
}
|
|
|
|
// 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(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::AppendTx
|
|
func (app *Basecoin) AppendTx(txBytes []byte) (res tmsp.Result) {
|
|
if len(txBytes) > maxTxSize {
|
|
return tmsp.ErrBaseEncodingError.AppendLog("Tx size exceeds maximum")
|
|
}
|
|
// Decode tx
|
|
var tx types.Tx
|
|
err := wire.ReadBinaryBytes(txBytes, &tx)
|
|
if err != nil {
|
|
return tmsp.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error())
|
|
}
|
|
// Validate and exec tx
|
|
res = state.ExecTx(app.state, app.plugins, tx, false, nil)
|
|
if res.IsErr() {
|
|
return res.PrependLog("Error in AppendTx")
|
|
}
|
|
return tmsp.OK
|
|
}
|
|
|
|
// TMSP::CheckTx
|
|
func (app *Basecoin) CheckTx(txBytes []byte) (res tmsp.Result) {
|
|
if len(txBytes) > maxTxSize {
|
|
return tmsp.ErrBaseEncodingError.AppendLog("Tx size exceeds maximum")
|
|
}
|
|
// Decode tx
|
|
var tx types.Tx
|
|
err := wire.ReadBinaryBytes(txBytes, &tx)
|
|
if err != nil {
|
|
return tmsp.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error())
|
|
}
|
|
// Validate tx
|
|
res = state.ExecTx(app.state, app.plugins, tx, true, nil)
|
|
if res.IsErr() {
|
|
return res.PrependLog("Error in CheckTx")
|
|
}
|
|
return tmsp.OK
|
|
}
|
|
|
|
// TMSP::Query
|
|
func (app *Basecoin) Query(query []byte) (res tmsp.Result) {
|
|
if len(query) == 0 {
|
|
return tmsp.ErrEncodingError.SetLog("Query cannot be zero length")
|
|
}
|
|
typeByte := query[0]
|
|
query = query[1:]
|
|
switch typeByte {
|
|
case typeByteBase:
|
|
return tmsp.OK.SetLog("This type of query not yet supported")
|
|
case typeByteEyes:
|
|
return app.eyesCli.QuerySync(query)
|
|
case typeByteGov:
|
|
return app.govMint.Query(query)
|
|
}
|
|
return tmsp.ErrBaseUnknownPlugin.SetLog(
|
|
Fmt("Unknown plugin with type byte %X", typeByte))
|
|
}
|
|
|
|
// TMSP::Commit
|
|
func (app *Basecoin) Commit() (res tmsp.Result) {
|
|
// First, commit all the plugins
|
|
for _, plugin := range app.plugins.GetList() {
|
|
res = plugin.Commit()
|
|
if res.IsErr() {
|
|
PanicSanity(Fmt("Error committing plugin %v", plugin.Name))
|
|
}
|
|
}
|
|
// Then, commit eyes.
|
|
res = app.eyesCli.CommitSync()
|
|
if res.IsErr() {
|
|
PanicSanity("Error getting hash: " + res.Error())
|
|
}
|
|
return res
|
|
}
|
|
|
|
// TMSP::InitChain
|
|
func (app *Basecoin) InitChain(validators []*tmsp.Validator) {
|
|
app.govMint.InitChain(validators)
|
|
}
|
|
|
|
// TMSP::EndBlock
|
|
func (app *Basecoin) EndBlock(height uint64) []*tmsp.Validator {
|
|
app.state.ResetCacheState()
|
|
return app.govMint.EndBlock(height)
|
|
}
|
|
|
|
//----------------------------------------
|
|
|
|
// Splits the string at the first :.
|
|
// if there are none, the second string is nil.
|
|
func splitKey(key string) (prefix string, sufix string) {
|
|
if strings.Contains(key, "/") {
|
|
keyParts := strings.SplitN(key, "/", 2)
|
|
return keyParts[0], keyParts[1]
|
|
}
|
|
return key, ""
|
|
}
|