Define Handler and Decorator

This commit is contained in:
Ethan Frey 2017-10-23 20:42:16 +02:00
parent babe854682
commit 362fbe6fe9
3 changed files with 207 additions and 144 deletions

96
decorators.go Normal file
View File

@ -0,0 +1,96 @@
package sdk
import (
"github.com/cosmos/cosmos-sdk/state"
)
// Decorator is anything that wraps another handler
// to enhance functionality.
//
// They are usually chained together via ChainDecorators
// before wrapping an interface.
type Decorator interface {
DecorateChecker
DecorateDeliverer
}
type DecorateChecker interface {
CheckTx(ctx Context, store state.SimpleDB,
tx interface{}, next Checker) (CheckResult, error)
}
type DecorateDeliverer interface {
DeliverTx(ctx Context, store state.SimpleDB, tx interface{},
next Deliverer) (DeliverResult, error)
}
// Stack is the entire application stack
type Stack struct {
decorators []Decorator
handler Handler
Handler // the compiled version, which we expose
}
var _ Handler = &Stack{}
// ChainDecorators prepares a stack of decorators,
// you must call `.WithHandler()` before you can execute it.
func ChainDecorators(decorators ...Decorator) *Stack {
s := &Stack{
decorators: decorators,
}
return s
}
// WithHandler sets the final handler for the stack and
// prepares it for use
func (s *Stack) WithHandler(handler Handler) *Stack {
if handler == nil {
panic("Cannot have a Stack without an end handler")
}
s.handler = handler
s.Handler = build(s.decorators, s.handler)
return s
}
// build wraps each decorator around the next, so that
// the last in the list is closest to the handler
func build(stack []Decorator, end Handler) Handler {
if len(stack) == 0 {
return end
}
return wrap(stack[0], build(stack[1:], end))
}
// decorator lets us wrap a whole stack up into one Handler
//
// heavily inspired by negroni's design
type decorator struct {
decorator Decorator
next Handler
}
// ensure it fulfils the interface
var _ Handler = &decorator{}
// CheckTx fulfils Handler interface
func (m *decorator) CheckTx(ctx Context, store state.SimpleDB,
tx interface{}) (CheckResult, error) {
return m.decorator.CheckTx(ctx, store, tx, m.next)
}
// DeliverTx fulfils Handler interface
func (m *decorator) DeliverTx(ctx Context, store state.SimpleDB,
tx interface{}) (res DeliverResult, err error) {
return m.decorator.DeliverTx(ctx, store, tx, m.next)
}
// wrap puts one decorator around a handler
func wrap(dec Decorator, next Handler) Handler {
return &decorator{
decorator: dec,
next: next,
}
}

View File

@ -2,7 +2,6 @@ package sdk
import (
abci "github.com/tendermint/abci/types"
"github.com/tendermint/go-wire/data"
"github.com/tendermint/tmlibs/log"
"github.com/cosmos/cosmos-sdk/state"
@ -15,24 +14,44 @@ const (
ChainKey = "chain_id"
)
// Handler is anything that processes a transaction
// Handler is anything that processes a transaction.
// Must handle checktx and delivertx
type Handler interface {
// Checker verifies there are valid fees and estimates work
Checker
// Deliver performs the tx once it makes it in the block
Deliver
// InitStater sets state from the genesis file
InitStater
// InitValidater sets the initial validator set
InitValidater
// Named ensures there is a name for the item
Named
// TODO????
// BeginBlock(store state.SimpleDB, hash []byte, header *abci.Header)
Deliverer
}
// Ticker can be executed every block
// Checker verifies there are valid fees and estimates work
type Checker interface {
CheckTx(ctx Context, store state.SimpleDB, tx interface{}) (CheckResult, error)
}
// CheckerFunc (like http.HandlerFunc) is a shortcut for making wrappers
type CheckerFunc func(Context, state.SimpleDB, interface{}) (CheckResult, error)
func (c CheckerFunc) CheckTx(ctx Context, store state.SimpleDB, tx interface{}) (CheckResult, error) {
return c(ctx, store, tx)
}
// Deliverer performs the tx once it makes it in the block
type Deliverer interface {
DeliverTx(ctx Context, store state.SimpleDB, tx interface{}) (DeliverResult, error)
}
// DelivererFunc (like http.HandlerFunc) is a shortcut for making wrappers
type DelivererFunc func(Context, state.SimpleDB, interface{}) (DeliverResult, error)
func (c DelivererFunc) DeliverTx(ctx Context, store state.SimpleDB, tx interface{}) (DeliverResult, error) {
return c(ctx, store, tx)
}
/////////////////////////////////////////////////
// Lifecycle actions, not tied to the tx handler
// Ticker can be executed every block.
// Called from BeginBlock
type Ticker interface {
Tick(Context, state.SimpleDB) ([]*abci.Validator, error)
}
@ -44,139 +63,17 @@ func (t TickerFunc) Tick(ctx Context, store state.SimpleDB) ([]*abci.Validator,
return t(ctx, store)
}
// Named ensures there is a name for the item
type Named interface {
Name() string
}
// Checker verifies there are valid fees and estimates work
type Checker interface {
CheckTx(ctx Context, store state.SimpleDB, tx Tx) (CheckResult, error)
}
// CheckerFunc (like http.HandlerFunc) is a shortcut for making wrappers
type CheckerFunc func(Context, state.SimpleDB, Tx) (CheckResult, error)
func (c CheckerFunc) CheckTx(ctx Context, store state.SimpleDB, tx Tx) (CheckResult, error) {
return c(ctx, store, tx)
}
// Deliver performs the tx once it makes it in the block
type Deliver interface {
DeliverTx(ctx Context, store state.SimpleDB, tx Tx) (DeliverResult, error)
}
// DeliverFunc (like http.HandlerFunc) is a shortcut for making wrappers
type DeliverFunc func(Context, state.SimpleDB, Tx) (DeliverResult, error)
func (c DeliverFunc) DeliverTx(ctx Context, store state.SimpleDB, tx Tx) (DeliverResult, error) {
return c(ctx, store, tx)
// InitValidator sets the initial validator set.
// Called from InitChain
type InitValidator interface {
InitValidators(logger log.Logger, store state.SimpleDB,
vals []*abci.Validator)
}
// InitStater sets state from the genesis file
//
// TODO: Think if this belongs here, in genesis, or somewhere else
type InitStater interface {
InitState(l log.Logger, store state.SimpleDB, module, key, value string) (string, error)
InitState(logger log.Logger, store state.SimpleDB,
module, key, value string) (string, error)
}
// InitStateFunc (like http.HandlerFunc) is a shortcut for making wrappers
type InitStateFunc func(log.Logger, state.SimpleDB, string, string, string) (string, error)
func (c InitStateFunc) InitState(l log.Logger, store state.SimpleDB, module, key, value string) (string, error) {
return c(l, store, module, key, value)
}
// InitValidater sets the initial validator set
type InitValidater interface {
InitValidate(log log.Logger, store state.SimpleDB, vals []*abci.Validator)
}
// InitValidateFunc (like http.HandlerFunc) is a shortcut for making wrappers
type InitValidateFunc func(log.Logger, state.SimpleDB, []*abci.Validator)
func (c InitValidateFunc) InitValidate(l log.Logger, store state.SimpleDB, vals []*abci.Validator) {
c(l, store, vals)
}
//---------- results and some wrappers --------
// Result is a common interface of CheckResult and GetResult
type Result interface {
GetData() data.Bytes
GetLog() string
}
func ToABCI(r Result) abci.Result {
return abci.Result{
Data: r.GetData(),
Log: r.GetLog(),
}
}
// CheckResult captures any non-error abci result
// to make sure people use error for error cases
type CheckResult struct {
Data data.Bytes
Log string
// GasAllocated is the maximum units of work we allow this tx to perform
GasAllocated uint64
// GasPayment is the total fees for this tx (or other source of payment)
GasPayment uint64
}
// NewCheck sets the gas used and the response data but no more info
// these are the most common info needed to be set by the Handler
func NewCheck(gasAllocated uint64, log string) CheckResult {
return CheckResult{
GasAllocated: gasAllocated,
Log: log,
}
}
var _ Result = CheckResult{}
func (r CheckResult) GetData() data.Bytes {
return r.Data
}
func (r CheckResult) GetLog() string {
return r.Log
}
// DeliverResult captures any non-error abci result
// to make sure people use error for error cases
type DeliverResult struct {
Data data.Bytes
Log string
Diff []*abci.Validator
GasUsed uint64
}
var _ Result = DeliverResult{}
func (r DeliverResult) GetData() data.Bytes {
return r.Data
}
func (r DeliverResult) GetLog() string {
return r.Log
}
// placeholders
// holders
type NopCheck struct{}
func (_ NopCheck) CheckTx(Context, state.SimpleDB, Tx) (r CheckResult, e error) { return }
type NopDeliver struct{}
func (_ NopDeliver) DeliverTx(Context, state.SimpleDB, Tx) (r DeliverResult, e error) { return }
type NopInitState struct{}
func (_ NopInitState) InitState(log.Logger, state.SimpleDB, string, string, string) (string, error) {
return "", nil
}
type NopInitValidate struct{}
func (_ NopInitValidate) InitValidate(log log.Logger, store state.SimpleDB, vals []*abci.Validator) {}

70
results.go Normal file
View File

@ -0,0 +1,70 @@
package sdk
import (
abci "github.com/tendermint/abci/types"
"github.com/tendermint/go-wire/data"
)
//---------- results and some wrappers --------
// Result is a common interface of CheckResult and GetResult
type Result interface {
GetData() data.Bytes
GetLog() string
}
func ToABCI(r Result) abci.Result {
return abci.Result{
Data: r.GetData(),
Log: r.GetLog(),
}
}
// CheckResult captures any non-error abci result
// to make sure people use error for error cases
type CheckResult struct {
Data data.Bytes
Log string
// GasAllocated is the maximum units of work we allow this tx to perform
GasAllocated uint64
// GasPayment is the total fees for this tx (or other source of payment)
GasPayment uint64
}
// NewCheck sets the gas used and the response data but no more info
// these are the most common info needed to be set by the Handler
func NewCheck(gasAllocated uint64, log string) CheckResult {
return CheckResult{
GasAllocated: gasAllocated,
Log: log,
}
}
var _ Result = CheckResult{}
func (r CheckResult) GetData() data.Bytes {
return r.Data
}
func (r CheckResult) GetLog() string {
return r.Log
}
// DeliverResult captures any non-error abci result
// to make sure people use error for error cases
type DeliverResult struct {
Data data.Bytes
Log string
Diff []*abci.Validator
GasUsed uint64
}
var _ Result = DeliverResult{}
func (r DeliverResult) GetData() data.Bytes {
return r.Data
}
func (r DeliverResult) GetLog() string {
return r.Log
}