Update decorators/handler/results.go add tx_msg/signature.go

This commit is contained in:
Jae Kwon 2017-11-26 14:14:03 -08:00
parent 6a9b8c3a92
commit 458fba22d3
11 changed files with 198 additions and 340 deletions

46
db.go
View File

@ -1,46 +0,0 @@
package sdk
import (
"github.com/tendermint/go-wire/data"
)
// KVStore is a simple interface to get/set data
type KVStore interface {
Set(key, value []byte)
Get(key []byte) (value []byte)
}
//----------------------------------------
// Model grabs together key and value to allow easier return values
type Model struct {
Key data.Bytes
Value data.Bytes
}
// SimpleDB allows us to do some basic range queries on a db
type SimpleDB interface {
KVStore
Has(key []byte) (has bool)
Remove(key []byte) (value []byte) // returns old value if there was one
// Start is inclusive, End is exclusive...
// Thus List ([]byte{12, 13}, []byte{12, 14}) will return anything with
// the prefix []byte{12, 13}
List(start, end []byte, limit int) []Model
First(start, end []byte) Model
Last(start, end []byte) Model
// Checkpoint returns the same state, but where writes
// are buffered and don't affect the parent
Checkpoint() SimpleDB
// Commit will take all changes from the checkpoint and write
// them to the parent.
// Returns an error if this is not a child of this one
Commit(SimpleDB) error
// Discard will remove reference to this
Discard()
}

View File

@ -1,92 +0,0 @@
package sdk
// 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 SimpleDB,
tx interface{}, next Checker) (CheckResult, error)
}
type DecorateDeliverer interface {
DeliverTx(ctx Context, store 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 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 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

@ -1,105 +0,0 @@
package sdk
import (
abci "github.com/tendermint/abci/types"
"github.com/tendermint/tmlibs/log"
)
const (
// ModuleNameBase is the module name for internal functionality
ModuleNameBase = "base"
// ChainKey is the option key for setting the chain id
ChainKey = "chain_id"
)
// 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
Deliverer
}
// Checker verifies there are valid fees and estimates work
type Checker interface {
CheckTx(ctx Context, store SimpleDB, tx interface{}) (CheckResult, error)
}
// CheckerFunc (like http.HandlerFunc) is a shortcut for making wrappers
type CheckerFunc func(Context, SimpleDB, interface{}) (CheckResult, error)
func (c CheckerFunc) CheckTx(ctx Context, store 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 SimpleDB, tx interface{}) (DeliverResult, error)
}
// DelivererFunc (like http.HandlerFunc) is a shortcut for making wrappers
type DelivererFunc func(Context, SimpleDB, interface{}) (DeliverResult, error)
func (c DelivererFunc) DeliverTx(ctx Context, store 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, SimpleDB) ([]*abci.Validator, error)
}
// TickerFunc allows a function to implement the interface
type TickerFunc func(Context, SimpleDB) ([]*abci.Validator, error)
func (t TickerFunc) Tick(ctx Context, store SimpleDB) ([]*abci.Validator, error) {
return t(ctx, store)
}
// InitValidator sets the initial validator set.
// Called from InitChain
type InitValidator interface {
InitValidators(logger log.Logger, store 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(logger log.Logger, store SimpleDB,
module, key, value string) (string, error)
}
//////////////////////////////////////////////////
// Helper methods
// Msg allows us to get the actual tx from a structure with lots of
// decorator information. This is usually what should be passed to Handlers.
type Msg interface {
GetTx() interface{}
}
// MustGetTx forces the msg to the interface and extracts the tx
func MustGetTx(msg interface{}) interface{} {
m := msg.(Msg)
return m.GetTx()
}
// WrapTx embeds the tx into a Msg interface, with no decorator info
func WrapTx(tx interface{}) Msg {
return msg{tx}
}
type msg struct {
tx interface{}
}
func (m msg) GetTx() interface{} {
return m.tx
}

View File

@ -1,70 +0,0 @@
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
}

86
types/decorators.go Normal file
View File

@ -0,0 +1,86 @@
package sdk
// A Decorator executes before/during/after a handler to enhance functionality.
type Decorator interface {
// Decorate Handler.CheckTx
CheckTx(ctx Context, ms MultiStore, tx Tx,
next CheckTxFunc) CheckResult
// Decorate Handler.DeliverTx
DeliverTx(ctx Context, ms MultiStore, tx Tx,
next DeliverTxFunc) DeliverResult
}
// A Decorator tied to its base handler "next" is itself a handler.
func Decorate(dec Decorator, next Handler) Handler {
return &decHandler{
decorator: dec,
next: next,
}
}
//----------------------------------------
/*
Helper to construct a decorated Handler from a stack of Decorators
(first-decorator-first-call as in Python @decorators) , w/ Handler provided
last for syntactic sugar of Stack().WithHandler()
Usage:
handler := sdk.Stack(
decorator1,
decorator2,
...,
).WithHandler(myHandler)
*/
func Stack(decorators ...Decorator) stack {
return stack{
decs: decorators,
}
}
// No need to expose this.
type stack struct {
decs []Decorator
}
// WithHandler sets the final handler for the stack and
// returns the decoratored Handler.
func (s *Stack) WithHandler(handler Handler) Handler {
if handler == nil {
panic("WithHandler() requires a non-nil Handler")
}
return build(s.decs, handler)
}
// 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 decHandler{
decorator: stack[0],
next: build(stack[1:], end),
}
}
//----------------------------------------
type decHandler struct {
decorator Decorator
next Handler
}
var _ Handler = &decHandler{}
func (dh *decHandler) CheckTx(ctx Context, ms MultiStore, tx Tx) CheckResult {
return dh.decorator.CheckTx(ctx, ms, tx, dh.next)
}
func (dh *decHandler) DeliverTx(ctx Context, ms MultiStore, tx Tx) DeliverResult {
return dh.decorator.DeliverTx(ctx, ms, tx, dh.next)
}

24
types/handler.go Normal file
View File

@ -0,0 +1,24 @@
package sdk
import (
abci "github.com/tendermint/abci/types"
"github.com/tendermint/tmlibs/log"
)
// Handler is something that processes a transaction.
type Handler interface {
// Checker verifies there are valid fees and estimates work.
CheckTx(ctx Context, ms MultiStore, tx Tx) CheckResult
// Deliverer performs the tx once it makes it in the block.
DeliverTx(ctx Context, ms MultiStore, tx Tx) DeliverResult
}
// Checker verifies there are valid fees and estimates work.
// NOTE: Keep in sync with Handler.CheckTx
type CheckTxFunc func(ctx Context, ms MultiStore, tx Tx) CheckResult
// Deliverer performs the tx once it makes it in the block.
// NOTE: Keep in sync with Handler.DeliverTx
type DeliverTxFunc func(ctx Context, ms MultiStore, tx Tx) DeliverResult

View File

@ -1,27 +0,0 @@
package types
import crypto "github.com/tendermint/go-crypto"
// The parsed tx bytes is called a Msg.
type Msg interface {
Get(key interface{}) (value interface{})
Origin() (tx []byte)
// Signers() returns the crypto.PubKey of signers
// responsible for signing the Msg.
// CONTRACT: All signatures must be present to be valid.
// CONTRACT: Returns pubkeys in some deterministic order
// CONTRACT: Get(MsgKeySigners) compatible.
Signers() []crypto.PubKey
// Signatures() returns the crypto.Signature of sigenrs
// who signed the Msg.
// CONTRACT: Length returned is same as length of
// pubkeys returned from MsgKeySigners, and the order
// matches.
// CONTRACT: If the signature is missing (ie the Msg is
// invalid), then the corresponding signature is
// .Empty().
// CONTRACT: Get(MsgKeySignatures) compatible.
Signatures() []crypto.Signature
}

29
types/results.go Normal file
View File

@ -0,0 +1,29 @@
package types
import (
abci "github.com/tendermint/abci/types"
)
// CheckResult captures any non-error ABCI result
// to make sure people use error for error cases.
type CheckResult struct {
abci.Result
// 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
}
// DeliverResult captures any non-error abci result
// to make sure people use error for error cases
type DeliverResult struct {
abci.Result
// TODO comment
Diff []*abci.Validator
// TODO comment
GasUsed uint64
}

23
types/signature.go Normal file
View File

@ -0,0 +1,23 @@
package types
import crypto "github.com/tendermint/go-crypto"
type Signature interface {
CryptoSig() crypto.Signature
Sequence() int
}
// StdSignature is a simple way to prevent replay attacks.
// There must be better strategies, but this is simplest.
type StdSignature struct {
crypto.Signature
Sequence int
}
func (ss StdSignature) CryptoSig() crypto.Signature {
return ss.Signature
}
func (ss StdSignature) Sequence() int {
return ss.Sequence
}

36
types/tx_msg.go Normal file
View File

@ -0,0 +1,36 @@
package types
type Msg interface {
// Get some property of the Msg.
Get(key interface{}) (value interface{})
// Get the canonical byte representation of the Msg.
SignBytes() []byte
// ValidateBasic does a simple validation check that
// doesn't require access to any other information.
ValidateBasic() error
// Signers returns the addrs of signers that must sign.
// CONTRACT: All signatures must be present to be valid.
// CONTRACT: Returns addrs in some deterministic order.
Signers() [][]byte
}
type Tx interface {
Msg
// Get the canonical byte representation of the Tx.
// Includes any signatures (or empty slots).
TxBytes() []byte
// Signatures returns the signature of signers who signed the Msg.
// CONTRACT: Length returned is same as length of
// pubkeys returned from MsgKeySigners, and the order
// matches.
// CONTRACT: If the signature is missing (ie the Msg is
// invalid), then the corresponding signature is
// .Empty().
Signatures() []Signature
}