Move ChainID into context
This commit is contained in:
parent
ef0ab758ed
commit
159574db89
175
app/app.go
175
app/app.go
|
@ -1,23 +1,22 @@
|
||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
wire "github.com/tendermint/go-wire"
|
"github.com/tendermint/basecoin"
|
||||||
eyes "github.com/tendermint/merkleeyes/client"
|
eyes "github.com/tendermint/merkleeyes/client"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
|
||||||
|
"github.com/tendermint/basecoin/errors"
|
||||||
|
"github.com/tendermint/basecoin/modules/coin"
|
||||||
|
"github.com/tendermint/basecoin/stack"
|
||||||
sm "github.com/tendermint/basecoin/state"
|
sm "github.com/tendermint/basecoin/state"
|
||||||
"github.com/tendermint/basecoin/types"
|
|
||||||
"github.com/tendermint/basecoin/version"
|
"github.com/tendermint/basecoin/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
maxTxSize = 10240
|
|
||||||
PluginNameBase = "base"
|
PluginNameBase = "base"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,23 +24,29 @@ type Basecoin struct {
|
||||||
eyesCli *eyes.Client
|
eyesCli *eyes.Client
|
||||||
state *sm.State
|
state *sm.State
|
||||||
cacheState *sm.State
|
cacheState *sm.State
|
||||||
plugins *types.Plugins
|
handler basecoin.Handler
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBasecoin(eyesCli *eyes.Client, l log.Logger) *Basecoin {
|
func NewBasecoin(h basecoin.Handler, eyesCli *eyes.Client, l log.Logger) *Basecoin {
|
||||||
state := sm.NewState(eyesCli, l.With("module", "state"))
|
state := sm.NewState(eyesCli, l.With("module", "state"))
|
||||||
|
|
||||||
plugins := types.NewPlugins()
|
|
||||||
return &Basecoin{
|
return &Basecoin{
|
||||||
|
handler: h,
|
||||||
eyesCli: eyesCli,
|
eyesCli: eyesCli,
|
||||||
state: state,
|
state: state,
|
||||||
cacheState: nil,
|
cacheState: nil,
|
||||||
plugins: plugins,
|
|
||||||
logger: l,
|
logger: l,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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!
|
// XXX For testing, not thread safe!
|
||||||
func (app *Basecoin) GetState() *sm.State {
|
func (app *Basecoin) GetState() *sm.State {
|
||||||
return app.state.CacheWrap()
|
return app.state.CacheWrap()
|
||||||
|
@ -60,87 +65,85 @@ func (app *Basecoin) Info() abci.ResponseInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *Basecoin) RegisterPlugin(plugin types.Plugin) {
|
|
||||||
app.plugins.RegisterPlugin(plugin)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ABCI::SetOption
|
// ABCI::SetOption
|
||||||
func (app *Basecoin) SetOption(key string, value string) string {
|
func (app *Basecoin) SetOption(key string, value string) string {
|
||||||
pluginName, key := splitKey(key)
|
// TODO
|
||||||
if pluginName != PluginNameBase {
|
return "todo"
|
||||||
// Set option on plugin
|
// pluginName, key := splitKey(key)
|
||||||
plugin := app.plugins.GetByName(pluginName)
|
// if pluginName != PluginNameBase {
|
||||||
if plugin == nil {
|
// // Set option on plugin
|
||||||
return "Invalid plugin name: " + pluginName
|
// plugin := app.plugins.GetByName(pluginName)
|
||||||
}
|
// if plugin == nil {
|
||||||
app.logger.Info("SetOption on plugin", "plugin", pluginName, "key", key, "value", value)
|
// return "Invalid plugin name: " + pluginName
|
||||||
return plugin.SetOption(app.state, key, value)
|
// }
|
||||||
} else {
|
// app.logger.Info("SetOption on plugin", "plugin", pluginName, "key", key, "value", value)
|
||||||
// Set option on basecoin
|
// return plugin.SetOption(app.state, key, value)
|
||||||
switch key {
|
// } else {
|
||||||
case "chain_id":
|
// // Set option on basecoin
|
||||||
app.state.SetChainID(value)
|
// switch key {
|
||||||
return "Success"
|
// case "chain_id":
|
||||||
case "account":
|
// app.state.SetChainID(value)
|
||||||
var acc GenesisAccount
|
// return "Success"
|
||||||
err := json.Unmarshal([]byte(value), &acc)
|
// case "account":
|
||||||
if err != nil {
|
// var acc GenesisAccount
|
||||||
return "Error decoding acc message: " + err.Error()
|
// err := json.Unmarshal([]byte(value), &acc)
|
||||||
}
|
// if err != nil {
|
||||||
acc.Balance.Sort()
|
// return "Error decoding acc message: " + err.Error()
|
||||||
addr, err := acc.GetAddr()
|
// }
|
||||||
if err != nil {
|
// acc.Balance.Sort()
|
||||||
return "Invalid address: " + err.Error()
|
// addr, err := acc.GetAddr()
|
||||||
}
|
// if err != nil {
|
||||||
app.state.SetAccount(addr, acc.ToAccount())
|
// return "Invalid address: " + err.Error()
|
||||||
app.logger.Info("SetAccount", "addr", hex.EncodeToString(addr), "acc", acc)
|
// }
|
||||||
|
// app.state.SetAccount(addr, acc.ToAccount())
|
||||||
|
// app.logger.Info("SetAccount", "addr", hex.EncodeToString(addr), "acc", acc)
|
||||||
|
|
||||||
return "Success"
|
// return "Success"
|
||||||
}
|
// }
|
||||||
return "Unrecognized option key " + key
|
// return "Unrecognized option key " + key
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ABCI::DeliverTx
|
// ABCI::DeliverTx
|
||||||
func (app *Basecoin) DeliverTx(txBytes []byte) (res abci.Result) {
|
func (app *Basecoin) DeliverTx(txBytes []byte) abci.Result {
|
||||||
if len(txBytes) > maxTxSize {
|
tx, err := basecoin.LoadTx(txBytes)
|
||||||
return abci.ErrBaseEncodingError.AppendLog("Tx size exceeds maximum")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode tx
|
|
||||||
var tx types.Tx
|
|
||||||
err := wire.ReadBinaryBytes(txBytes, &tx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return abci.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error())
|
return errors.Result(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate and exec tx
|
// TODO: can we abstract this setup and commit logic??
|
||||||
res = sm.ExecTx(app.state, app.plugins, tx, false, nil)
|
cache := app.state.CacheWrap()
|
||||||
if res.IsErr() {
|
ctx := stack.NewContext(app.state.GetChainID(),
|
||||||
return res.PrependLog("Error in DeliverTx")
|
app.logger.With("call", "delivertx"))
|
||||||
|
res, err := app.handler.DeliverTx(ctx, cache, tx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// discard the cache...
|
||||||
|
return errors.Result(err)
|
||||||
}
|
}
|
||||||
return res
|
// commit the cache and return result
|
||||||
|
cache.CacheSync()
|
||||||
|
return res.ToABCI()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ABCI::CheckTx
|
// ABCI::CheckTx
|
||||||
func (app *Basecoin) CheckTx(txBytes []byte) (res abci.Result) {
|
func (app *Basecoin) CheckTx(txBytes []byte) abci.Result {
|
||||||
if len(txBytes) > maxTxSize {
|
tx, err := basecoin.LoadTx(txBytes)
|
||||||
return abci.ErrBaseEncodingError.AppendLog("Tx size exceeds maximum")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode tx
|
|
||||||
var tx types.Tx
|
|
||||||
err := wire.ReadBinaryBytes(txBytes, &tx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return abci.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error())
|
return errors.Result(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate tx
|
// TODO: can we abstract this setup and commit logic??
|
||||||
res = sm.ExecTx(app.cacheState, app.plugins, tx, true, nil)
|
ctx := stack.NewContext(app.state.GetChainID(),
|
||||||
if res.IsErr() {
|
app.logger.With("call", "checktx"))
|
||||||
return res.PrependLog("Error in 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)
|
||||||
}
|
}
|
||||||
return abci.OK
|
return res.ToABCI()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ABCI::Query
|
// ABCI::Query
|
||||||
|
@ -151,12 +154,6 @@ func (app *Basecoin) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQu
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle special path for account info
|
|
||||||
if reqQuery.Path == "/account" {
|
|
||||||
reqQuery.Path = "/key"
|
|
||||||
reqQuery.Data = types.AccountKey(reqQuery.Data)
|
|
||||||
}
|
|
||||||
|
|
||||||
resQuery, err := app.eyesCli.QuerySync(reqQuery)
|
resQuery, err := app.eyesCli.QuerySync(reqQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resQuery.Log = "Failed to query MerkleEyes: " + err.Error()
|
resQuery.Log = "Failed to query MerkleEyes: " + err.Error()
|
||||||
|
@ -183,24 +180,24 @@ func (app *Basecoin) Commit() (res abci.Result) {
|
||||||
|
|
||||||
// ABCI::InitChain
|
// ABCI::InitChain
|
||||||
func (app *Basecoin) InitChain(validators []*abci.Validator) {
|
func (app *Basecoin) InitChain(validators []*abci.Validator) {
|
||||||
for _, plugin := range app.plugins.GetList() {
|
// for _, plugin := range app.plugins.GetList() {
|
||||||
plugin.InitChain(app.state, validators)
|
// plugin.InitChain(app.state, validators)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ABCI::BeginBlock
|
// ABCI::BeginBlock
|
||||||
func (app *Basecoin) BeginBlock(hash []byte, header *abci.Header) {
|
func (app *Basecoin) BeginBlock(hash []byte, header *abci.Header) {
|
||||||
for _, plugin := range app.plugins.GetList() {
|
// for _, plugin := range app.plugins.GetList() {
|
||||||
plugin.BeginBlock(app.state, hash, header)
|
// plugin.BeginBlock(app.state, hash, header)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ABCI::EndBlock
|
// ABCI::EndBlock
|
||||||
func (app *Basecoin) EndBlock(height uint64) (res abci.ResponseEndBlock) {
|
func (app *Basecoin) EndBlock(height uint64) (res abci.ResponseEndBlock) {
|
||||||
for _, plugin := range app.plugins.GetList() {
|
// for _, plugin := range app.plugins.GetList() {
|
||||||
pluginRes := plugin.EndBlock(app.state, height)
|
// pluginRes := plugin.EndBlock(app.state, height)
|
||||||
res.Diffs = append(res.Diffs, pluginRes.Diffs...)
|
// res.Diffs = append(res.Diffs, pluginRes.Diffs...)
|
||||||
}
|
// }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,8 @@ func (at *appTest) reset() {
|
||||||
at.accOut = types.MakeAcc("output0")
|
at.accOut = types.MakeAcc("output0")
|
||||||
|
|
||||||
eyesCli := eyes.NewLocalClient("", 0)
|
eyesCli := eyes.NewLocalClient("", 0)
|
||||||
at.app = NewBasecoin(eyesCli, log.TestingLogger().With("module", "app"))
|
at.app = NewBasecoin(DefaultHandler(), eyesCli,
|
||||||
|
log.TestingLogger().With("module", "app"))
|
||||||
|
|
||||||
res := at.app.SetOption("base/chain_id", at.chainID)
|
res := at.app.SetOption("base/chain_id", at.chainID)
|
||||||
require.EqualValues(at.t, res, "Success")
|
require.EqualValues(at.t, res, "Success")
|
||||||
|
@ -105,7 +106,8 @@ func TestSetOption(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
eyesCli := eyes.NewLocalClient("", 0)
|
eyesCli := eyes.NewLocalClient("", 0)
|
||||||
app := NewBasecoin(eyesCli, log.TestingLogger().With("module", "app"))
|
app := NewBasecoin(DefaultHandler(), eyesCli,
|
||||||
|
log.TestingLogger().With("module", "app"))
|
||||||
|
|
||||||
//testing ChainID
|
//testing ChainID
|
||||||
chainID := "testChain"
|
chainID := "testChain"
|
||||||
|
|
|
@ -19,7 +19,7 @@ const genesisAcctFilepath = "./testdata/genesis2.json"
|
||||||
|
|
||||||
func TestLoadGenesisDoNotFailIfAppOptionsAreMissing(t *testing.T) {
|
func TestLoadGenesisDoNotFailIfAppOptionsAreMissing(t *testing.T) {
|
||||||
eyesCli := eyescli.NewLocalClient("", 0)
|
eyesCli := eyescli.NewLocalClient("", 0)
|
||||||
app := NewBasecoin(eyesCli, log.TestingLogger())
|
app := NewBasecoin(DefaultHandler(), eyesCli, log.TestingLogger())
|
||||||
err := app.LoadGenesis("./testdata/genesis3.json")
|
err := app.LoadGenesis("./testdata/genesis3.json")
|
||||||
require.Nil(t, err, "%+v", err)
|
require.Nil(t, err, "%+v", err)
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ func TestLoadGenesis(t *testing.T) {
|
||||||
assert, require := assert.New(t), require.New(t)
|
assert, require := assert.New(t), require.New(t)
|
||||||
|
|
||||||
eyesCli := eyescli.NewLocalClient("", 0)
|
eyesCli := eyescli.NewLocalClient("", 0)
|
||||||
app := NewBasecoin(eyesCli, log.TestingLogger())
|
app := NewBasecoin(DefaultHandler(), eyesCli, log.TestingLogger())
|
||||||
err := app.LoadGenesis(genesisFilepath)
|
err := app.LoadGenesis(genesisFilepath)
|
||||||
require.Nil(err, "%+v", err)
|
require.Nil(err, "%+v", err)
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ func TestLoadGenesisAccountAddress(t *testing.T) {
|
||||||
assert, require := assert.New(t), require.New(t)
|
assert, require := assert.New(t), require.New(t)
|
||||||
|
|
||||||
eyesCli := eyescli.NewLocalClient("", 0)
|
eyesCli := eyescli.NewLocalClient("", 0)
|
||||||
app := NewBasecoin(eyesCli, log.TestingLogger())
|
app := NewBasecoin(DefaultHandler(), eyesCli, log.TestingLogger())
|
||||||
err := app.LoadGenesis(genesisAcctFilepath)
|
err := app.LoadGenesis(genesisAcctFilepath)
|
||||||
require.Nil(err, "%+v", err)
|
require.Nil(err, "%+v", err)
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
"github.com/tendermint/abci/server"
|
"github.com/tendermint/abci/server"
|
||||||
|
"github.com/tendermint/basecoin"
|
||||||
eyesApp "github.com/tendermint/merkleeyes/app"
|
eyesApp "github.com/tendermint/merkleeyes/app"
|
||||||
eyes "github.com/tendermint/merkleeyes/client"
|
eyes "github.com/tendermint/merkleeyes/client"
|
||||||
"github.com/tendermint/tmlibs/cli"
|
"github.com/tendermint/tmlibs/cli"
|
||||||
|
@ -21,6 +22,8 @@ import (
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
"github.com/tendermint/basecoin/app"
|
"github.com/tendermint/basecoin/app"
|
||||||
|
"github.com/tendermint/basecoin/modules/coin"
|
||||||
|
"github.com/tendermint/basecoin/stack"
|
||||||
)
|
)
|
||||||
|
|
||||||
var StartCmd = &cobra.Command{
|
var StartCmd = &cobra.Command{
|
||||||
|
@ -48,6 +51,22 @@ func init() {
|
||||||
tcmd.AddNodeFlags(StartCmd)
|
tcmd.AddNodeFlags(StartCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: setup handler instead of Plugins
|
||||||
|
func getHandler() basecoin.Handler {
|
||||||
|
// use the default stack
|
||||||
|
h := coin.NewHandler()
|
||||||
|
app := stack.NewDefault("change-this").Use(h)
|
||||||
|
return app
|
||||||
|
|
||||||
|
// register IBC plugn
|
||||||
|
// basecoinApp.RegisterPlugin(NewIBCPlugin())
|
||||||
|
|
||||||
|
// register all other plugins
|
||||||
|
// for _, p := range plugins {
|
||||||
|
// basecoinApp.RegisterPlugin(p.newPlugin())
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
func startCmd(cmd *cobra.Command, args []string) error {
|
func startCmd(cmd *cobra.Command, args []string) error {
|
||||||
rootDir := viper.GetString(cli.HomeFlag)
|
rootDir := viper.GetString(cli.HomeFlag)
|
||||||
meyes := viper.GetString(FlagEyes)
|
meyes := viper.GetString(FlagEyes)
|
||||||
|
@ -66,15 +85,8 @@ func startCmd(cmd *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Basecoin app
|
// Create Basecoin app
|
||||||
basecoinApp := app.NewBasecoin(eyesCli, logger.With("module", "app"))
|
h := app.DefaultHandler()
|
||||||
|
basecoinApp := app.NewBasecoin(h, eyesCli, logger.With("module", "app"))
|
||||||
// register IBC plugn
|
|
||||||
// basecoinApp.RegisterPlugin(NewIBCPlugin())
|
|
||||||
|
|
||||||
// register all other plugins
|
|
||||||
for _, p := range plugins {
|
|
||||||
basecoinApp.RegisterPlugin(p.newPlugin())
|
|
||||||
}
|
|
||||||
|
|
||||||
// if chain_id has not been set yet, load the genesis.
|
// if chain_id has not been set yet, load the genesis.
|
||||||
// else, assume it's been loaded
|
// else, assume it's been loaded
|
||||||
|
|
|
@ -34,4 +34,5 @@ type Context interface {
|
||||||
HasPermission(perm Actor) bool
|
HasPermission(perm Actor) bool
|
||||||
IsParent(ctx Context) bool
|
IsParent(ctx Context) bool
|
||||||
Reset() Context
|
Reset() Context
|
||||||
|
ChainID() string
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ func TestHandlerValidation(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
ctx := stack.MockContext().WithPermissions(tc.perms...)
|
ctx := stack.MockContext("base-chain").WithPermissions(tc.perms...)
|
||||||
_, err := checkTx(ctx, tc.tx)
|
_, err := checkTx(ctx, tc.tx)
|
||||||
if tc.valid {
|
if tc.valid {
|
||||||
assert.Nil(err, "%d: %+v", i, err)
|
assert.Nil(err, "%d: %+v", i, err)
|
||||||
|
@ -142,7 +142,7 @@ func TestDeliverTx(t *testing.T) {
|
||||||
require.Nil(err, "%d: %+v", i, err)
|
require.Nil(err, "%d: %+v", i, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := stack.MockContext().WithPermissions(tc.perms...)
|
ctx := stack.MockContext("base-chain").WithPermissions(tc.perms...)
|
||||||
_, err := h.DeliverTx(ctx, store, tc.tx)
|
_, err := h.DeliverTx(ctx, store, tc.tx)
|
||||||
if len(tc.final) > 0 { // valid
|
if len(tc.final) > 0 { // valid
|
||||||
assert.Nil(err, "%d: %+v", i, err)
|
assert.Nil(err, "%d: %+v", i, err)
|
||||||
|
|
|
@ -12,9 +12,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Chain enforces that this tx was bound to the named chain
|
// Chain enforces that this tx was bound to the named chain
|
||||||
type Chain struct {
|
type Chain struct{}
|
||||||
ChainID string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ Chain) Name() string {
|
func (_ Chain) Name() string {
|
||||||
return NameRecovery
|
return NameRecovery
|
||||||
|
@ -23,7 +21,7 @@ func (_ Chain) Name() string {
|
||||||
var _ Middleware = Chain{}
|
var _ Middleware = Chain{}
|
||||||
|
|
||||||
func (c Chain) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) {
|
func (c Chain) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) {
|
||||||
stx, err := c.checkChain(tx)
|
stx, err := c.checkChain(ctx.ChainID(), tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
@ -31,7 +29,7 @@ func (c Chain) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Chain) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) {
|
func (c Chain) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) {
|
||||||
stx, err := c.checkChain(tx)
|
stx, err := c.checkChain(ctx.ChainID(), tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
@ -39,12 +37,12 @@ func (c Chain) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkChain makes sure the tx is a txs.Chain and
|
// checkChain makes sure the tx is a txs.Chain and
|
||||||
func (c Chain) checkChain(tx basecoin.Tx) (basecoin.Tx, error) {
|
func (c Chain) checkChain(chainID string, tx basecoin.Tx) (basecoin.Tx, error) {
|
||||||
ctx, ok := tx.Unwrap().(*txs.Chain)
|
ctx, ok := tx.Unwrap().(*txs.Chain)
|
||||||
if !ok {
|
if !ok {
|
||||||
return tx, errors.ErrNoChain()
|
return tx, errors.ErrNoChain()
|
||||||
}
|
}
|
||||||
if ctx.ChainID != c.ChainID {
|
if ctx.ChainID != chainID {
|
||||||
return tx, errors.ErrWrongChain(ctx.ChainID)
|
return tx, errors.ErrWrongChain(ctx.ChainID)
|
||||||
}
|
}
|
||||||
return ctx.Tx, nil
|
return ctx.Tx, nil
|
||||||
|
|
|
@ -30,12 +30,12 @@ func TestChain(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// generic args here...
|
// generic args here...
|
||||||
ctx := NewContext(log.NewNopLogger())
|
ctx := NewContext(chainID, log.NewNopLogger())
|
||||||
store := types.NewMemKVStore()
|
store := types.NewMemKVStore()
|
||||||
|
|
||||||
// build the stack
|
// build the stack
|
||||||
ok := OKHandler{msg}
|
ok := OKHandler{msg}
|
||||||
app := New(Chain{chainID}).Use(ok)
|
app := New(Chain{}).Use(ok)
|
||||||
|
|
||||||
for idx, tc := range cases {
|
for idx, tc := range cases {
|
||||||
i := strconv.Itoa(idx)
|
i := strconv.Itoa(idx)
|
||||||
|
|
|
@ -17,20 +17,26 @@ type nonce int64
|
||||||
|
|
||||||
type secureContext struct {
|
type secureContext struct {
|
||||||
id nonce
|
id nonce
|
||||||
|
chain string
|
||||||
app string
|
app string
|
||||||
perms []basecoin.Actor
|
perms []basecoin.Actor
|
||||||
log.Logger
|
log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContext(logger log.Logger) basecoin.Context {
|
func NewContext(chain string, logger log.Logger) basecoin.Context {
|
||||||
return secureContext{
|
return secureContext{
|
||||||
id: nonce(rand.Int63()),
|
id: nonce(rand.Int63()),
|
||||||
|
chain: chain,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ basecoin.Context = secureContext{}
|
var _ basecoin.Context = secureContext{}
|
||||||
|
|
||||||
|
func (c secureContext) ChainID() string {
|
||||||
|
return c.chain
|
||||||
|
}
|
||||||
|
|
||||||
// WithPermissions will panic if they try to set permission without the proper app
|
// WithPermissions will panic if they try to set permission without the proper app
|
||||||
func (c secureContext) WithPermissions(perms ...basecoin.Actor) basecoin.Context {
|
func (c secureContext) WithPermissions(perms ...basecoin.Actor) basecoin.Context {
|
||||||
// the guard makes sure you only set permissions for the app you are inside
|
// the guard makes sure you only set permissions for the app you are inside
|
||||||
|
@ -44,6 +50,7 @@ func (c secureContext) WithPermissions(perms ...basecoin.Actor) basecoin.Context
|
||||||
|
|
||||||
return secureContext{
|
return secureContext{
|
||||||
id: c.id,
|
id: c.id,
|
||||||
|
chain: c.chain,
|
||||||
app: c.app,
|
app: c.app,
|
||||||
perms: append(c.perms, perms...),
|
perms: append(c.perms, perms...),
|
||||||
Logger: c.Logger,
|
Logger: c.Logger,
|
||||||
|
@ -73,6 +80,7 @@ func (c secureContext) IsParent(other basecoin.Context) bool {
|
||||||
func (c secureContext) Reset() basecoin.Context {
|
func (c secureContext) Reset() basecoin.Context {
|
||||||
return secureContext{
|
return secureContext{
|
||||||
id: c.id,
|
id: c.id,
|
||||||
|
chain: c.chain,
|
||||||
app: c.app,
|
app: c.app,
|
||||||
perms: nil,
|
perms: nil,
|
||||||
Logger: c.Logger,
|
Logger: c.Logger,
|
||||||
|
@ -88,6 +96,7 @@ func withApp(ctx basecoin.Context, app string) basecoin.Context {
|
||||||
}
|
}
|
||||||
return secureContext{
|
return secureContext{
|
||||||
id: sc.id,
|
id: sc.id,
|
||||||
|
chain: sc.chain,
|
||||||
app: app,
|
app: app,
|
||||||
perms: sc.perms,
|
perms: sc.perms,
|
||||||
Logger: sc.Logger,
|
Logger: sc.Logger,
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
func TestOK(t *testing.T) {
|
func TestOK(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
ctx := NewContext(log.NewNopLogger())
|
ctx := NewContext("test-chain", log.NewNopLogger())
|
||||||
store := types.NewMemKVStore()
|
store := types.NewMemKVStore()
|
||||||
data := "this looks okay"
|
data := "this looks okay"
|
||||||
tx := basecoin.Tx{}
|
tx := basecoin.Tx{}
|
||||||
|
@ -33,7 +33,7 @@ func TestOK(t *testing.T) {
|
||||||
func TestFail(t *testing.T) {
|
func TestFail(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
ctx := NewContext(log.NewNopLogger())
|
ctx := NewContext("test-chain", log.NewNopLogger())
|
||||||
store := types.NewMemKVStore()
|
store := types.NewMemKVStore()
|
||||||
msg := "big problem"
|
msg := "big problem"
|
||||||
tx := basecoin.Tx{}
|
tx := basecoin.Tx{}
|
||||||
|
@ -53,7 +53,7 @@ func TestFail(t *testing.T) {
|
||||||
func TestPanic(t *testing.T) {
|
func TestPanic(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
ctx := NewContext(log.NewNopLogger())
|
ctx := NewContext("test-chain", log.NewNopLogger())
|
||||||
store := types.NewMemKVStore()
|
store := types.NewMemKVStore()
|
||||||
msg := "system crash!"
|
msg := "system crash!"
|
||||||
tx := basecoin.Tx{}
|
tx := basecoin.Tx{}
|
||||||
|
|
|
@ -57,12 +57,12 @@ func New(middlewares ...Middleware) *Stack {
|
||||||
// NewDefault sets up the common middlewares before your custom stack.
|
// NewDefault sets up the common middlewares before your custom stack.
|
||||||
//
|
//
|
||||||
// This is logger, recovery, signature, and chain
|
// This is logger, recovery, signature, and chain
|
||||||
func NewDefault(chainID string, middlewares ...Middleware) *Stack {
|
func NewDefault(middlewares ...Middleware) *Stack {
|
||||||
mids := []Middleware{
|
mids := []Middleware{
|
||||||
Logger{},
|
Logger{},
|
||||||
Recovery{},
|
Recovery{},
|
||||||
Signatures{},
|
Signatures{},
|
||||||
Chain{chainID},
|
Chain{},
|
||||||
}
|
}
|
||||||
mids = append(mids, middlewares...)
|
mids = append(mids, middlewares...)
|
||||||
return New(mids...)
|
return New(mids...)
|
||||||
|
|
|
@ -17,7 +17,7 @@ func TestPermissionSandbox(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
// generic args
|
// generic args
|
||||||
ctx := NewContext(log.NewNopLogger())
|
ctx := NewContext("test-chain", log.NewNopLogger())
|
||||||
store := types.NewMemKVStore()
|
store := types.NewMemKVStore()
|
||||||
raw := txs.NewRaw([]byte{1, 2, 3, 4})
|
raw := txs.NewRaw([]byte{1, 2, 3, 4})
|
||||||
rawBytes, err := data.ToWire(raw)
|
rawBytes, err := data.ToWire(raw)
|
||||||
|
|
|
@ -10,17 +10,23 @@ import (
|
||||||
|
|
||||||
type mockContext struct {
|
type mockContext struct {
|
||||||
perms []basecoin.Actor
|
perms []basecoin.Actor
|
||||||
|
chain string
|
||||||
log.Logger
|
log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func MockContext() basecoin.Context {
|
func MockContext(chain string) basecoin.Context {
|
||||||
return mockContext{
|
return mockContext{
|
||||||
|
chain: chain,
|
||||||
Logger: log.NewNopLogger(),
|
Logger: log.NewNopLogger(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ basecoin.Context = mockContext{}
|
var _ basecoin.Context = mockContext{}
|
||||||
|
|
||||||
|
func (c mockContext) ChainID() string {
|
||||||
|
return c.chain
|
||||||
|
}
|
||||||
|
|
||||||
// WithPermissions will panic if they try to set permission without the proper app
|
// WithPermissions will panic if they try to set permission without the proper app
|
||||||
func (c mockContext) WithPermissions(perms ...basecoin.Actor) basecoin.Context {
|
func (c mockContext) WithPermissions(perms ...basecoin.Actor) basecoin.Context {
|
||||||
return mockContext{
|
return mockContext{
|
||||||
|
|
|
@ -15,7 +15,7 @@ func TestRecovery(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
// generic args here...
|
// generic args here...
|
||||||
ctx := NewContext(log.NewNopLogger())
|
ctx := NewContext("test-chain", log.NewNopLogger())
|
||||||
store := types.NewMemKVStore()
|
store := types.NewMemKVStore()
|
||||||
tx := basecoin.Tx{}
|
tx := basecoin.Tx{}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ func TestSignatureChecks(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
// generic args
|
// generic args
|
||||||
ctx := NewContext(log.NewNopLogger())
|
ctx := NewContext("test-chain", log.NewNopLogger())
|
||||||
store := types.NewMemKVStore()
|
store := types.NewMemKVStore()
|
||||||
raw := txs.NewRaw([]byte{1, 2, 3, 4})
|
raw := txs.NewRaw([]byte{1, 2, 3, 4})
|
||||||
|
|
||||||
|
|
21
tx.go
21
tx.go
|
@ -1,5 +1,12 @@
|
||||||
package basecoin
|
package basecoin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/tendermint/go-wire/data"
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxTxSize = 10240
|
||||||
|
|
||||||
// TxInner is the interface all concrete transactions should implement.
|
// TxInner is the interface all concrete transactions should implement.
|
||||||
//
|
//
|
||||||
// It adds bindings for clean un/marhsaling of the various implementations
|
// It adds bindings for clean un/marhsaling of the various implementations
|
||||||
|
@ -15,6 +22,20 @@ type TxInner interface {
|
||||||
ValidateBasic() error
|
ValidateBasic() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadTx parses a tx from data
|
||||||
|
//
|
||||||
|
// TODO: label both errors with abci.CodeType_EncodingError
|
||||||
|
// need to move errors to avoid import cycle
|
||||||
|
func LoadTx(bin []byte) (tx Tx, err error) {
|
||||||
|
if len(bin) > maxTxSize {
|
||||||
|
return tx, errors.New("Tx size exceeds maximum")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode tx
|
||||||
|
err = data.FromWire(bin, &tx)
|
||||||
|
return tx, err
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: do we need this abstraction? TxLayer???
|
// TODO: do we need this abstraction? TxLayer???
|
||||||
// please review again after implementing "middleware"
|
// please review again after implementing "middleware"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue