Add SetOption to all middleware and handlers
This commit is contained in:
parent
159574db89
commit
fa1a300943
@ -55,7 +55,7 @@ func init() {
|
||||
func getHandler() basecoin.Handler {
|
||||
// use the default stack
|
||||
h := coin.NewHandler()
|
||||
app := stack.NewDefault("change-this").Use(h)
|
||||
app := stack.NewDefault().Use(h)
|
||||
return app
|
||||
|
||||
// register IBC plugn
|
||||
|
||||
@ -7,27 +7,34 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/app"
|
||||
"github.com/tendermint/basecoin/modules/coin"
|
||||
"github.com/tendermint/basecoin/stack"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
"github.com/tendermint/go-wire"
|
||||
eyescli "github.com/tendermint/merkleeyes/client"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
// TODO: actually handle the counter here...
|
||||
func CounterHandler() basecoin.Handler {
|
||||
// use the default stack
|
||||
h := coin.NewHandler()
|
||||
return stack.NewDefault().Use(h)
|
||||
}
|
||||
|
||||
func TestCounterPlugin(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
// Basecoin initialization
|
||||
eyesCli := eyescli.NewLocalClient("", 0)
|
||||
chainID := "test_chain_id"
|
||||
bcApp := app.NewBasecoin(eyesCli, log.TestingLogger().With("module", "app"))
|
||||
bcApp := app.NewBasecoin(CounterHandler(), eyesCli,
|
||||
log.TestingLogger().With("module", "app"))
|
||||
bcApp.SetOption("base/chain_id", chainID)
|
||||
// t.Log(bcApp.Info())
|
||||
|
||||
// Add Counter plugin
|
||||
counterPlugin := New()
|
||||
bcApp.RegisterPlugin(counterPlugin)
|
||||
|
||||
// Account initialization
|
||||
test1PrivAcc := types.PrivAccountFromSecret("test1")
|
||||
|
||||
@ -44,7 +51,7 @@ func TestCounterPlugin(t *testing.T) {
|
||||
tx := &types.AppTx{
|
||||
Gas: gas,
|
||||
Fee: fee,
|
||||
Name: counterPlugin.Name(),
|
||||
Name: "counter",
|
||||
Input: types.NewTxInput(test1Acc.PubKey, inputCoins, inputSequence),
|
||||
Data: wire.BinaryBytes(CounterTx{Valid: true, Fee: appFee}),
|
||||
}
|
||||
|
||||
49
handler.go
49
handler.go
@ -3,10 +3,24 @@ package basecoin
|
||||
import (
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/go-wire/data"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
|
||||
// Handler is anything that processes a transaction
|
||||
type Handler interface {
|
||||
Checker
|
||||
Deliver
|
||||
SetOptioner
|
||||
Named
|
||||
// TODO: flesh these out as well
|
||||
// SetOption(store types.KVStore, key, value string) (log string)
|
||||
// InitChain(store types.KVStore, vals []*abci.Validator)
|
||||
// BeginBlock(store types.KVStore, hash []byte, header *abci.Header)
|
||||
// EndBlock(store types.KVStore, height uint64) abci.ResponseEndBlock
|
||||
}
|
||||
|
||||
type Named interface {
|
||||
Name() string
|
||||
}
|
||||
@ -33,16 +47,15 @@ func (c DeliverFunc) DeliverTx(ctx Context, store types.KVStore, tx Tx) (Result,
|
||||
return c(ctx, store, tx)
|
||||
}
|
||||
|
||||
// Handler is anything that processes a transaction
|
||||
type Handler interface {
|
||||
Checker
|
||||
Deliver
|
||||
Named
|
||||
// TODO: flesh these out as well
|
||||
// SetOption(store types.KVStore, key, value string) (log string)
|
||||
// InitChain(store types.KVStore, vals []*abci.Validator)
|
||||
// BeginBlock(store types.KVStore, hash []byte, header *abci.Header)
|
||||
// EndBlock(store types.KVStore, height uint64) abci.ResponseEndBlock
|
||||
type SetOptioner interface {
|
||||
SetOption(l log.Logger, store types.KVStore, key, value string) (string, error)
|
||||
}
|
||||
|
||||
// SetOptionFunc (like http.HandlerFunc) is a shortcut for making wrapers
|
||||
type SetOptionFunc func(log.Logger, types.KVStore, string, string) (string, error)
|
||||
|
||||
func (c SetOptionFunc) SetOption(l log.Logger, store types.KVStore, key, value string) (string, error) {
|
||||
return c(l, store, key, value)
|
||||
}
|
||||
|
||||
// Result captures any non-error abci result
|
||||
@ -58,3 +71,19 @@ func (r Result) ToABCI() abci.Result {
|
||||
Log: r.Log,
|
||||
}
|
||||
}
|
||||
|
||||
// placeholders
|
||||
// holders
|
||||
type NopCheck struct{}
|
||||
|
||||
func (_ NopCheck) CheckTx(Context, types.KVStore, Tx) (r Result, e error) { return }
|
||||
|
||||
type NopDeliver struct{}
|
||||
|
||||
func (_ NopDeliver) DeliverTx(Context, types.KVStore, Tx) (r Result, e error) { return }
|
||||
|
||||
type NopOption struct{}
|
||||
|
||||
func (_ NopOption) SetOption(log.Logger, types.KVStore, string, string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package coin
|
||||
|
||||
import (
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
@ -74,6 +76,11 @@ func (h Handler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoi
|
||||
return basecoin.Result{}, nil
|
||||
}
|
||||
|
||||
func (h Handler) SetOption(l log.Logger, store types.KVStore, key, value string) (log string, err error) {
|
||||
// TODO
|
||||
return "ok", nil
|
||||
}
|
||||
|
||||
func checkTx(ctx basecoin.Context, tx basecoin.Tx) (send SendTx, err error) {
|
||||
// check if the tx is proper type and valid
|
||||
send, ok := tx.Unwrap().(SendTx)
|
||||
|
||||
@ -23,6 +23,7 @@ type AccountChecker interface {
|
||||
type SimpleFeeHandler struct {
|
||||
AccountChecker
|
||||
MinFee types.Coins
|
||||
stack.PassOption
|
||||
}
|
||||
|
||||
func (_ SimpleFeeHandler) Name() string {
|
||||
|
||||
@ -12,7 +12,9 @@ const (
|
||||
)
|
||||
|
||||
// Chain enforces that this tx was bound to the named chain
|
||||
type Chain struct{}
|
||||
type Chain struct {
|
||||
PassOption
|
||||
}
|
||||
|
||||
func (_ Chain) Name() string {
|
||||
return NameRecovery
|
||||
|
||||
@ -34,7 +34,7 @@ func TestChain(t *testing.T) {
|
||||
store := types.NewMemKVStore()
|
||||
|
||||
// build the stack
|
||||
ok := OKHandler{msg}
|
||||
ok := OKHandler{Log: msg}
|
||||
app := New(Chain{}).Use(ok)
|
||||
|
||||
for idx, tc := range cases {
|
||||
|
||||
@ -19,6 +19,7 @@ const (
|
||||
// OKHandler just used to return okay to everything
|
||||
type OKHandler struct {
|
||||
Log string
|
||||
basecoin.NopOption
|
||||
}
|
||||
|
||||
var _ basecoin.Handler = OKHandler{}
|
||||
@ -38,7 +39,9 @@ func (ok OKHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx base
|
||||
}
|
||||
|
||||
// EchoHandler returns success, echoing res.Data = tx bytes
|
||||
type EchoHandler struct{}
|
||||
type EchoHandler struct {
|
||||
basecoin.NopOption
|
||||
}
|
||||
|
||||
var _ basecoin.Handler = EchoHandler{}
|
||||
|
||||
@ -61,6 +64,7 @@ func (_ EchoHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx bas
|
||||
// FailHandler always returns an error
|
||||
type FailHandler struct {
|
||||
Err error
|
||||
basecoin.NopOption
|
||||
}
|
||||
|
||||
var _ basecoin.Handler = FailHandler{}
|
||||
@ -83,6 +87,7 @@ func (f FailHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx bas
|
||||
type PanicHandler struct {
|
||||
Msg string
|
||||
Err error
|
||||
basecoin.NopOption
|
||||
}
|
||||
|
||||
var _ basecoin.Handler = PanicHandler{}
|
||||
|
||||
@ -20,7 +20,7 @@ func TestOK(t *testing.T) {
|
||||
data := "this looks okay"
|
||||
tx := basecoin.Tx{}
|
||||
|
||||
ok := OKHandler{data}
|
||||
ok := OKHandler{Log: data}
|
||||
res, err := ok.CheckTx(ctx, store, tx)
|
||||
assert.Nil(err, "%+v", err)
|
||||
assert.Equal(data, res.Log)
|
||||
@ -38,7 +38,7 @@ func TestFail(t *testing.T) {
|
||||
msg := "big problem"
|
||||
tx := basecoin.Tx{}
|
||||
|
||||
fail := FailHandler{errors.New(msg)}
|
||||
fail := FailHandler{Err: errors.New(msg)}
|
||||
_, err := fail.CheckTx(ctx, store, tx)
|
||||
if assert.NotNil(err) {
|
||||
assert.Equal(msg, err.Error())
|
||||
|
||||
@ -15,6 +15,7 @@ const (
|
||||
// Required Actor, otherwise passes along the call untouched
|
||||
type CheckMiddleware struct {
|
||||
Required basecoin.Actor
|
||||
PassOption
|
||||
}
|
||||
|
||||
var _ Middleware = CheckMiddleware{}
|
||||
@ -40,6 +41,7 @@ func (p CheckMiddleware) DeliverTx(ctx basecoin.Context, store types.KVStore, tx
|
||||
// GrantMiddleware tries to set the permission to this Actor, which may be prohibited
|
||||
type GrantMiddleware struct {
|
||||
Auth basecoin.Actor
|
||||
PassOption
|
||||
}
|
||||
|
||||
var _ Middleware = GrantMiddleware{}
|
||||
|
||||
@ -1,18 +1,12 @@
|
||||
package stack
|
||||
|
||||
import (
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
|
||||
type CheckerMiddle interface {
|
||||
CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (basecoin.Result, error)
|
||||
}
|
||||
|
||||
type DeliverMiddle interface {
|
||||
DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (basecoin.Result, error)
|
||||
}
|
||||
|
||||
// Middleware is anything that wraps another handler to enhance functionality.
|
||||
//
|
||||
// You can use utilities in handlers to construct them, the interfaces
|
||||
@ -20,5 +14,55 @@ type DeliverMiddle interface {
|
||||
type Middleware interface {
|
||||
CheckerMiddle
|
||||
DeliverMiddle
|
||||
SetOptionMiddle
|
||||
basecoin.Named
|
||||
}
|
||||
|
||||
type CheckerMiddle interface {
|
||||
CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (basecoin.Result, error)
|
||||
}
|
||||
|
||||
type CheckerMiddleFunc func(basecoin.Context, types.KVStore, basecoin.Tx, basecoin.Checker) (basecoin.Result, error)
|
||||
|
||||
func (c CheckerMiddleFunc) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (basecoin.Result, error) {
|
||||
return c(ctx, store, tx, next)
|
||||
}
|
||||
|
||||
type DeliverMiddle interface {
|
||||
DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (basecoin.Result, error)
|
||||
}
|
||||
|
||||
type DeliverMiddleFunc func(basecoin.Context, types.KVStore, basecoin.Tx, basecoin.Deliver) (basecoin.Result, error)
|
||||
|
||||
func (d DeliverMiddleFunc) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (basecoin.Result, error) {
|
||||
return d(ctx, store, tx, next)
|
||||
}
|
||||
|
||||
type SetOptionMiddle interface {
|
||||
SetOption(l log.Logger, store types.KVStore, key, value string, next basecoin.SetOptioner) (string, error)
|
||||
}
|
||||
|
||||
type SetOptionMiddleFunc func(log.Logger, types.KVStore, string, string, basecoin.SetOptioner) (string, error)
|
||||
|
||||
func (c SetOptionMiddleFunc) SetOption(l log.Logger, store types.KVStore, key, value string, next basecoin.SetOptioner) (string, error) {
|
||||
return c(l, store, key, value, next)
|
||||
}
|
||||
|
||||
// holders
|
||||
type PassCheck struct{}
|
||||
|
||||
func (_ PassCheck) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (basecoin.Result, error) {
|
||||
return next.CheckTx(ctx, store, tx)
|
||||
}
|
||||
|
||||
type PassDeliver struct{}
|
||||
|
||||
func (_ PassDeliver) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (basecoin.Result, error) {
|
||||
return next.DeliverTx(ctx, store, tx)
|
||||
}
|
||||
|
||||
type PassOption struct{}
|
||||
|
||||
func (_ PassOption) SetOption(l log.Logger, store types.KVStore, key, value string, next basecoin.SetOptioner) (string, error) {
|
||||
return next.SetOption(l, store, key, value)
|
||||
}
|
||||
|
||||
@ -3,6 +3,8 @@ package stack
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
@ -48,6 +50,20 @@ func (_ Logger) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin
|
||||
return
|
||||
}
|
||||
|
||||
func (_ Logger) SetOption(l log.Logger, store types.KVStore, key, value string, next basecoin.SetOptioner) (string, error) {
|
||||
start := time.Now()
|
||||
res, err := next.SetOption(l, store, key, value)
|
||||
delta := time.Now().Sub(start)
|
||||
// TODO: log the value being set also?
|
||||
l = l.With("duration", micros(delta)).With("key", key)
|
||||
if err == nil {
|
||||
l.Info("SetOption", "log", res)
|
||||
} else {
|
||||
l.Error("SetOption", "err", err)
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
// micros returns how many microseconds passed in a call
|
||||
func micros(d time.Duration) int {
|
||||
return int(d.Seconds() * 1000000)
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package stack
|
||||
|
||||
import (
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
@ -37,6 +39,10 @@ func (m *middleware) DeliverTx(ctx basecoin.Context, store types.KVStore, tx bas
|
||||
return m.middleware.DeliverTx(ctx, store, tx, next)
|
||||
}
|
||||
|
||||
func (m *middleware) SetOption(l log.Logger, store types.KVStore, key, value string) (string, error) {
|
||||
return m.middleware.SetOption(l, store, key, value, m.next)
|
||||
}
|
||||
|
||||
// Stack is the entire application stack
|
||||
type Stack struct {
|
||||
middles []Middleware
|
||||
|
||||
@ -42,8 +42,8 @@ func TestPermissionSandbox(t *testing.T) {
|
||||
for i, tc := range cases {
|
||||
app := New(
|
||||
Recovery{}, // we need this so panics turn to errors
|
||||
GrantMiddleware{tc.grant},
|
||||
CheckMiddleware{tc.require},
|
||||
GrantMiddleware{Auth: tc.grant},
|
||||
CheckMiddleware{Required: tc.require},
|
||||
).Use(EchoHandler{})
|
||||
|
||||
res, err := app.CheckTx(ctx, store, raw)
|
||||
|
||||
@ -14,7 +14,9 @@ const (
|
||||
NameMultiplexer = "mplx"
|
||||
)
|
||||
|
||||
type Multiplexer struct{}
|
||||
type Multiplexer struct {
|
||||
PassOption
|
||||
}
|
||||
|
||||
func (_ Multiplexer) Name() string {
|
||||
return NameMultiplexer
|
||||
|
||||
@ -3,6 +3,8 @@ package stack
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
@ -39,6 +41,15 @@ func (_ Recovery) DeliverTx(ctx basecoin.Context, store types.KVStore, tx baseco
|
||||
return next.DeliverTx(ctx, store, tx)
|
||||
}
|
||||
|
||||
func (_ Recovery) SetOption(l log.Logger, store types.KVStore, key, value string, next basecoin.SetOptioner) (log string, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = normalizePanic(r)
|
||||
}
|
||||
}()
|
||||
return next.SetOption(l, store, key, value)
|
||||
}
|
||||
|
||||
// normalizePanic makes sure we can get a nice TMError (with stack) out of it
|
||||
func normalizePanic(p interface{}) error {
|
||||
if err, isErr := p.(error); isErr {
|
||||
|
||||
@ -13,7 +13,9 @@ const (
|
||||
NameSigs = "sigs"
|
||||
)
|
||||
|
||||
type Signatures struct{}
|
||||
type Signatures struct {
|
||||
PassOption
|
||||
}
|
||||
|
||||
func (_ Signatures) Name() string {
|
||||
return NameSigs
|
||||
|
||||
@ -58,7 +58,7 @@ func TestSignatureChecks(t *testing.T) {
|
||||
app := New(
|
||||
Recovery{}, // we need this so panics turn to errors
|
||||
Signatures{},
|
||||
CheckMiddleware{tc.check},
|
||||
CheckMiddleware{Required: tc.check},
|
||||
).Use(OKHandler{})
|
||||
|
||||
var tx basecoin.Tx
|
||||
|
||||
Loading…
Reference in New Issue
Block a user