Define Handler and Decorator
This commit is contained in:
parent
babe854682
commit
362fbe6fe9
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
185
handler.go
185
handler.go
|
@ -2,7 +2,6 @@ package sdk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
"github.com/tendermint/go-wire/data"
|
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/state"
|
"github.com/cosmos/cosmos-sdk/state"
|
||||||
|
@ -15,24 +14,44 @@ const (
|
||||||
ChainKey = "chain_id"
|
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 {
|
type Handler interface {
|
||||||
// Checker verifies there are valid fees and estimates work
|
// Checker verifies there are valid fees and estimates work
|
||||||
Checker
|
Checker
|
||||||
// Deliver performs the tx once it makes it in the block
|
// Deliver performs the tx once it makes it in the block
|
||||||
Deliver
|
Deliverer
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
type Ticker interface {
|
||||||
Tick(Context, state.SimpleDB) ([]*abci.Validator, error)
|
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)
|
return t(ctx, store)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Named ensures there is a name for the item
|
// InitValidator sets the initial validator set.
|
||||||
type Named interface {
|
// Called from InitChain
|
||||||
Name() string
|
type InitValidator interface {
|
||||||
}
|
InitValidators(logger log.Logger, store state.SimpleDB,
|
||||||
|
vals []*abci.Validator)
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitStater sets state from the genesis file
|
// InitStater sets state from the genesis file
|
||||||
|
//
|
||||||
|
// TODO: Think if this belongs here, in genesis, or somewhere else
|
||||||
type InitStater interface {
|
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) {}
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
Loading…
Reference in New Issue