Plugin support for SetOption, Query, and Commit
This commit is contained in:
parent
964a4cfd50
commit
601a654b7d
88
app/app.go
88
app/app.go
|
@ -1,6 +1,8 @@
|
||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/tendermint/basecoin/state"
|
"github.com/tendermint/basecoin/state"
|
||||||
"github.com/tendermint/basecoin/types"
|
"github.com/tendermint/basecoin/types"
|
||||||
. "github.com/tendermint/go-common"
|
. "github.com/tendermint/go-common"
|
||||||
|
@ -22,7 +24,7 @@ type Basecoin struct {
|
||||||
func NewBasecoin(eyesCli *eyes.Client) *Basecoin {
|
func NewBasecoin(eyesCli *eyes.Client) *Basecoin {
|
||||||
state_ := state.NewState(eyesCli)
|
state_ := state.NewState(eyesCli)
|
||||||
govMint := gov.NewGovernmint(eyesCli)
|
govMint := gov.NewGovernmint(eyesCli)
|
||||||
state_.RegisterPlugin([]byte("gov"), govMint)
|
state_.RegisterPlugin("GOV", govMint)
|
||||||
return &Basecoin{
|
return &Basecoin{
|
||||||
eyesCli: eyesCli,
|
eyesCli: eyesCli,
|
||||||
govMint: govMint,
|
govMint: govMint,
|
||||||
|
@ -37,25 +39,37 @@ func (app *Basecoin) Info() string {
|
||||||
|
|
||||||
// TMSP::SetOption
|
// TMSP::SetOption
|
||||||
func (app *Basecoin) SetOption(key string, value string) (log string) {
|
func (app *Basecoin) SetOption(key string, value string) (log string) {
|
||||||
switch key {
|
|
||||||
case "chainID":
|
pluginName, key := splitKey(key)
|
||||||
app.state.SetChainID(value)
|
if pluginName != "BASE" {
|
||||||
return "Success"
|
// Set option on plugin
|
||||||
case "account":
|
plugin := app.state.GetPlugin(pluginName)
|
||||||
var err error
|
if plugin == nil {
|
||||||
var setAccount types.Account
|
return "Invalid plugin name: " + pluginName
|
||||||
wire.ReadJSONPtr(&setAccount, []byte(value), &err)
|
|
||||||
if err != nil {
|
|
||||||
return "Error decoding setAccount message: " + err.Error()
|
|
||||||
}
|
}
|
||||||
accBytes := wire.BinaryBytes(setAccount)
|
return plugin.SetOption(key, value)
|
||||||
res := app.eyesCli.SetSync(setAccount.PubKey.Address(), accBytes)
|
} else {
|
||||||
if res.IsErr() {
|
// Set option on basecoin
|
||||||
return "Error saving account: " + res.Error()
|
switch key {
|
||||||
|
case "chainID":
|
||||||
|
app.state.SetChainID(value)
|
||||||
|
return "Success"
|
||||||
|
case "account":
|
||||||
|
var err error
|
||||||
|
var setAccount types.Account
|
||||||
|
wire.ReadJSONPtr(&setAccount, []byte(value), &err)
|
||||||
|
if err != nil {
|
||||||
|
return "Error decoding setAccount message: " + err.Error()
|
||||||
|
}
|
||||||
|
accBytes := wire.BinaryBytes(setAccount)
|
||||||
|
res := app.eyesCli.SetSync(setAccount.PubKey.Address(), accBytes)
|
||||||
|
if res.IsErr() {
|
||||||
|
return "Error saving account: " + res.Error()
|
||||||
|
}
|
||||||
|
return "Success"
|
||||||
}
|
}
|
||||||
return "Success"
|
return "Unrecognized option key " + key
|
||||||
}
|
}
|
||||||
return "Unrecognized option key " + key
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TMSP::AppendTx
|
// TMSP::AppendTx
|
||||||
|
@ -98,18 +112,36 @@ func (app *Basecoin) CheckTx(txBytes []byte) (res tmsp.Result) {
|
||||||
|
|
||||||
// TMSP::Query
|
// TMSP::Query
|
||||||
func (app *Basecoin) Query(query []byte) (res tmsp.Result) {
|
func (app *Basecoin) Query(query []byte) (res tmsp.Result) {
|
||||||
res = app.eyesCli.GetSync(query)
|
pluginName, queryStr := splitKey(string(query))
|
||||||
if res.IsErr() {
|
if pluginName != "BASE" {
|
||||||
return res.PrependLog("Error querying eyesCli")
|
plugin := app.state.GetPlugin(pluginName)
|
||||||
|
if plugin == nil {
|
||||||
|
return tmsp.ErrBaseUnknownPlugin.SetLog(Fmt("Unknown plugin %v", pluginName))
|
||||||
|
}
|
||||||
|
return plugin.Query([]byte(queryStr))
|
||||||
|
} else {
|
||||||
|
// TODO turn Basecoin ops into a plugin?
|
||||||
|
res = app.eyesCli.GetSync([]byte(queryStr))
|
||||||
|
if res.IsErr() {
|
||||||
|
return res.PrependLog("Error querying eyesCli")
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TMSP::Commit
|
// TMSP::Commit
|
||||||
func (app *Basecoin) Commit() (res tmsp.Result) {
|
func (app *Basecoin) Commit() (res tmsp.Result) {
|
||||||
|
// First, commit all the plugins
|
||||||
|
for _, plugin := range app.state.GetPlugins() {
|
||||||
|
res = plugin.Commit()
|
||||||
|
if res.IsErr() {
|
||||||
|
PanicSanity(Fmt("Error committing plugin %v", plugin.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Then, commit eyes.
|
||||||
res = app.eyesCli.CommitSync()
|
res = app.eyesCli.CommitSync()
|
||||||
if res.IsErr() {
|
if res.IsErr() {
|
||||||
panic("Error getting hash: " + res.Error())
|
PanicSanity("Error getting hash: " + res.Error())
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -124,3 +156,15 @@ func (app *Basecoin) EndBlock(height uint64) []*tmsp.Validator {
|
||||||
app.state.ResetCacheState()
|
app.state.ResetCacheState()
|
||||||
return app.govMint.EndBlock(height)
|
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, ""
|
||||||
|
}
|
||||||
|
|
|
@ -93,9 +93,9 @@ func ExecTx(state *State, tx types.Tx, isCheckTx bool, evc events.Fireable) tmsp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate call address
|
// Validate call address
|
||||||
plugin := state.GetPlugin(tx.Address)
|
plugin := state.GetPlugin(string(tx.Address))
|
||||||
if plugin != nil {
|
if plugin != nil {
|
||||||
return tmsp.ErrBaseUnknownAddress.AppendLog(Fmt("Unrecognized address %X", tx.Address))
|
return tmsp.ErrBaseUnknownAddress.AppendLog(Fmt("Unrecognized address %X (%v)", tx.Address, string(tx.Address)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Good!
|
// Good!
|
||||||
|
|
|
@ -8,10 +8,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
chainID string
|
chainID string
|
||||||
eyesCli *eyes.Client
|
eyesCli *eyes.Client
|
||||||
checkCache map[string]checkAccount
|
checkCache map[string]checkAccount
|
||||||
plugins map[string]types.Plugin
|
plugins map[string]types.Plugin
|
||||||
|
pluginsList []types.NamedPlugin
|
||||||
|
|
||||||
LastBlockHeight uint64
|
LastBlockHeight uint64
|
||||||
LastBlockHash []byte
|
LastBlockHash []byte
|
||||||
|
@ -23,6 +24,7 @@ func NewState(eyesCli *eyes.Client) *State {
|
||||||
chainID: "",
|
chainID: "",
|
||||||
eyesCli: eyesCli,
|
eyesCli: eyesCli,
|
||||||
checkCache: make(map[string]checkAccount),
|
checkCache: make(map[string]checkAccount),
|
||||||
|
plugins: make(map[string]types.Plugin),
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -38,12 +40,20 @@ func (s *State) GetChainID() string {
|
||||||
return s.chainID
|
return s.chainID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) RegisterPlugin(addr []byte, plugin types.Plugin) {
|
func (s *State) RegisterPlugin(name string, plugin types.Plugin) {
|
||||||
s.plugins[string(addr)] = plugin
|
s.plugins[name] = plugin
|
||||||
|
s.pluginsList = append(s.pluginsList, types.NamedPlugin{
|
||||||
|
Name: name,
|
||||||
|
Plugin: plugin,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) GetPlugin(addr []byte) types.Plugin {
|
func (s *State) GetPlugin(name string) types.Plugin {
|
||||||
return s.plugins[string(addr)]
|
return s.plugins[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *State) GetPlugins() []types.NamedPlugin {
|
||||||
|
return s.pluginsList
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
|
@ -8,17 +8,16 @@ import (
|
||||||
"github.com/tendermint/basecoin/types"
|
"github.com/tendermint/basecoin/types"
|
||||||
. "github.com/tendermint/go-common"
|
. "github.com/tendermint/go-common"
|
||||||
"github.com/tendermint/go-wire"
|
"github.com/tendermint/go-wire"
|
||||||
|
govtypes "github.com/tendermint/governmint/types"
|
||||||
eyescli "github.com/tendermint/merkleeyes/client"
|
eyescli "github.com/tendermint/merkleeyes/client"
|
||||||
_ "github.com/tendermint/tendermint/rpc/core/types" // Register RPCResponse > Result types
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
Get the "test" account.
|
|
||||||
PrivKey: 019F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A0867D3B5EAF0C0BF6B5A602D359DAECC86A7A74053490EC37AE08E71360587C870
|
|
||||||
PubKey: 0167D3B5EAF0C0BF6B5A602D359DAECC86A7A74053490EC37AE08E71360587C870
|
|
||||||
Address: D9B727742AA29FA638DC63D70813C976014C4CE0
|
|
||||||
*/
|
|
||||||
func main() {
|
func main() {
|
||||||
|
//testSendTx()
|
||||||
|
testGov()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSendTx() {
|
||||||
eyesCli := eyescli.NewLocalClient()
|
eyesCli := eyescli.NewLocalClient()
|
||||||
bcApp := app.NewBasecoin(eyesCli)
|
bcApp := app.NewBasecoin(eyesCli)
|
||||||
fmt.Println(bcApp.Info())
|
fmt.Println(bcApp.Info())
|
||||||
|
@ -61,4 +60,27 @@ func main() {
|
||||||
txBytes := wire.BinaryBytes(tx)
|
txBytes := wire.BinaryBytes(tx)
|
||||||
res := bcApp.AppendTx(txBytes)
|
res := bcApp.AppendTx(txBytes)
|
||||||
fmt.Println(res)
|
fmt.Println(res)
|
||||||
|
if res.IsErr() {
|
||||||
|
Exit(Fmt("Failed: %v", res.Error()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGov() {
|
||||||
|
eyesCli := eyescli.NewLocalClient()
|
||||||
|
bcApp := app.NewBasecoin(eyesCli)
|
||||||
|
fmt.Println(bcApp.Info())
|
||||||
|
|
||||||
|
tPriv := tests.PrivAccountFromSecret("test")
|
||||||
|
|
||||||
|
// Seed Basecoin with admin using PrivAccount
|
||||||
|
tAcc := tPriv.Account
|
||||||
|
adminEntity := govtypes.Entity{
|
||||||
|
ID: "",
|
||||||
|
PubKey: tAcc.PubKey,
|
||||||
|
}
|
||||||
|
log := bcApp.SetOption("GOV:admin", string(wire.JSONBytes(adminEntity)))
|
||||||
|
if log != "Success" {
|
||||||
|
Exit(Fmt("Failed to set option: %v", log))
|
||||||
|
}
|
||||||
|
// TODO test proposals or something.
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,15 @@ import (
|
||||||
// Gas is a pointer to remainig gas. Decrement as you go,
|
// Gas is a pointer to remainig gas. Decrement as you go,
|
||||||
// if any gas is left the user is
|
// if any gas is left the user is
|
||||||
type Plugin interface {
|
type Plugin interface {
|
||||||
CallTx(ctx CallContext, txBytes []byte) tmsp.Result
|
SetOption(key string, value string) (log string)
|
||||||
|
CallTx(ctx CallContext, txBytes []byte) (res tmsp.Result)
|
||||||
|
Query(query []byte) (res tmsp.Result)
|
||||||
|
Commit() (res tmsp.Result)
|
||||||
|
}
|
||||||
|
|
||||||
|
type NamedPlugin struct {
|
||||||
|
Name string
|
||||||
|
Plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
type CallContext struct {
|
type CallContext struct {
|
||||||
|
|
Loading…
Reference in New Issue