Cleanup base module -> util
This commit is contained in:
parent
362fbe6fe9
commit
a90741f2df
|
@ -1,68 +0,0 @@
|
|||
package base
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk"
|
||||
"github.com/cosmos/cosmos-sdk/stack"
|
||||
"github.com/cosmos/cosmos-sdk/state"
|
||||
)
|
||||
|
||||
//nolint
|
||||
const (
|
||||
NameChain = "chain"
|
||||
)
|
||||
|
||||
// Chain enforces that this tx was bound to the named chain
|
||||
type Chain struct {
|
||||
stack.PassInitState
|
||||
stack.PassInitValidate
|
||||
}
|
||||
|
||||
// Name of the module - fulfills Middleware interface
|
||||
func (Chain) Name() string {
|
||||
return NameChain
|
||||
}
|
||||
|
||||
var _ stack.Middleware = Chain{}
|
||||
|
||||
// CheckTx makes sure we are on the proper chain - fulfills Middlware interface
|
||||
func (c Chain) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Checker) (res sdk.CheckResult, err error) {
|
||||
stx, err := c.checkChainTx(ctx.ChainID(), ctx.BlockHeight(), tx)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
return next.CheckTx(ctx, store, stx)
|
||||
}
|
||||
|
||||
// DeliverTx makes sure we are on the proper chain - fulfills Middlware interface
|
||||
func (c Chain) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Deliver) (res sdk.DeliverResult, err error) {
|
||||
stx, err := c.checkChainTx(ctx.ChainID(), ctx.BlockHeight(), tx)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
return next.DeliverTx(ctx, store, stx)
|
||||
}
|
||||
|
||||
// checkChainTx makes sure the tx is a Chain Tx, it is on the proper chain,
|
||||
// and it has not expired.
|
||||
func (c Chain) checkChainTx(chainID string, height uint64, tx sdk.Tx) (sdk.Tx, error) {
|
||||
// make sure it is a chaintx
|
||||
ctx, ok := tx.Unwrap().(ChainTx)
|
||||
if !ok {
|
||||
return tx, ErrNoChain()
|
||||
}
|
||||
|
||||
// basic validation
|
||||
err := ctx.ValidateBasic()
|
||||
if err != nil {
|
||||
return tx, err
|
||||
}
|
||||
|
||||
// compare against state
|
||||
if ctx.ChainID != chainID {
|
||||
return tx, ErrWrongChain(ctx.ChainID)
|
||||
}
|
||||
if ctx.ExpiresAt != 0 && ctx.ExpiresAt <= height {
|
||||
return tx, ErrExpired()
|
||||
}
|
||||
return ctx.Tx, nil
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
package base
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk"
|
||||
"github.com/cosmos/cosmos-sdk/stack"
|
||||
"github.com/cosmos/cosmos-sdk/state"
|
||||
)
|
||||
|
||||
// nolint
|
||||
const (
|
||||
NameLogger = "lggr"
|
||||
)
|
||||
|
||||
// Logger catches any panics and returns them as errors instead
|
||||
type Logger struct{}
|
||||
|
||||
// Name of the module - fulfills Middleware interface
|
||||
func (Logger) Name() string {
|
||||
return NameLogger
|
||||
}
|
||||
|
||||
var _ stack.Middleware = Logger{}
|
||||
|
||||
// CheckTx logs time and result - fulfills Middlware interface
|
||||
func (Logger) CheckTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Checker) (res sdk.CheckResult, err error) {
|
||||
start := time.Now()
|
||||
res, err = next.CheckTx(ctx, store, tx)
|
||||
delta := time.Now().Sub(start)
|
||||
// TODO: log some info on the tx itself?
|
||||
l := ctx.With("duration", micros(delta))
|
||||
if err == nil {
|
||||
l.Debug("CheckTx", "log", res.Log)
|
||||
} else {
|
||||
l.Info("CheckTx", "err", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeliverTx logs time and result - fulfills Middlware interface
|
||||
func (Logger) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx, next sdk.Deliver) (res sdk.DeliverResult, err error) {
|
||||
start := time.Now()
|
||||
res, err = next.DeliverTx(ctx, store, tx)
|
||||
delta := time.Now().Sub(start)
|
||||
// TODO: log some info on the tx itself?
|
||||
l := ctx.With("duration", micros(delta))
|
||||
if err == nil {
|
||||
l.Info("DeliverTx", "log", res.Log)
|
||||
} else {
|
||||
l.Error("DeliverTx", "err", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// InitState logs time and result - fulfills Middlware interface
|
||||
func (Logger) InitState(l log.Logger, store state.SimpleDB, module, key, value string, next sdk.InitStater) (string, error) {
|
||||
start := time.Now()
|
||||
res, err := next.InitState(l, store, module, key, value)
|
||||
delta := time.Now().Sub(start)
|
||||
// TODO: log the value being set also?
|
||||
l = l.With("duration", micros(delta)).With("mod", module).With("key", key)
|
||||
if err == nil {
|
||||
l.Info("InitState", "log", res)
|
||||
} else {
|
||||
l.Error("InitState", "err", err)
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
// InitValidate logs time and result - fulfills Middlware interface
|
||||
func (Logger) InitValidate(l log.Logger, store state.SimpleDB, vals []*abci.Validator, next sdk.InitValidater) {
|
||||
start := time.Now()
|
||||
next.InitValidate(l, store, vals)
|
||||
delta := time.Now().Sub(start)
|
||||
l = l.With("duration", micros(delta))
|
||||
l.Info("InitValidate")
|
||||
}
|
||||
|
||||
// micros returns how many microseconds passed in a call
|
||||
func micros(d time.Duration) int {
|
||||
return int(d.Seconds() * 1000000)
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
package base
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk"
|
||||
"github.com/cosmos/cosmos-sdk/errors"
|
||||
)
|
||||
|
||||
// nolint
|
||||
const (
|
||||
// for utils...
|
||||
ByteMultiTx = 0x2
|
||||
ByteChainTx = 0x3
|
||||
)
|
||||
|
||||
//nolint
|
||||
const (
|
||||
TypeMultiTx = NameMultiplexer + "/tx"
|
||||
TypeChainTx = NameChain + "/tx"
|
||||
)
|
||||
|
||||
func init() {
|
||||
sdk.TxMapper.
|
||||
RegisterImplementation(MultiTx{}, TypeMultiTx, ByteMultiTx).
|
||||
RegisterImplementation(ChainTx{}, TypeChainTx, ByteChainTx)
|
||||
}
|
||||
|
||||
/**** MultiTx ******/
|
||||
|
||||
// MultiTx - a transaction containing multiple transactions
|
||||
type MultiTx struct {
|
||||
Txs []sdk.Tx `json:"txs"`
|
||||
}
|
||||
|
||||
var _ sdk.TxInner = &MultiTx{}
|
||||
|
||||
//nolint - TxInner Functions
|
||||
func NewMultiTx(txs ...sdk.Tx) sdk.Tx {
|
||||
return (MultiTx{Txs: txs}).Wrap()
|
||||
}
|
||||
func (mt MultiTx) Wrap() sdk.Tx {
|
||||
return sdk.Tx{mt}
|
||||
}
|
||||
func (mt MultiTx) ValidateBasic() error {
|
||||
for _, t := range mt.Txs {
|
||||
err := t.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/*** ChainTx ****/
|
||||
|
||||
// ChainTx locks this tx to one chainTx, wrap with this before signing
|
||||
type ChainTx struct {
|
||||
// name of chain, must be [A-Za-z0-9_-]+
|
||||
ChainID string `json:"chain_id"`
|
||||
// block height at which it is no longer valid, 0 means no expiration
|
||||
ExpiresAt uint64 `json:"expires_at"`
|
||||
Tx sdk.Tx `json:"tx"`
|
||||
}
|
||||
|
||||
var _ sdk.TxInner = &ChainTx{}
|
||||
|
||||
var (
|
||||
chainPattern = regexp.MustCompile("^[A-Za-z0-9_-]+$")
|
||||
)
|
||||
|
||||
// NewChainTx wraps a particular tx with the ChainTx wrapper,
|
||||
// to enforce chain and height
|
||||
func NewChainTx(chainID string, expires uint64, tx sdk.Tx) sdk.Tx {
|
||||
c := ChainTx{
|
||||
ChainID: chainID,
|
||||
ExpiresAt: expires,
|
||||
Tx: tx,
|
||||
}
|
||||
return c.Wrap()
|
||||
}
|
||||
|
||||
//nolint - TxInner Functions
|
||||
func (c ChainTx) Wrap() sdk.Tx {
|
||||
return sdk.Tx{c}
|
||||
}
|
||||
func (c ChainTx) ValidateBasic() error {
|
||||
if c.ChainID == "" {
|
||||
return ErrNoChain()
|
||||
}
|
||||
if !chainPattern.MatchString(c.ChainID) {
|
||||
return ErrWrongChain(c.ChainID)
|
||||
}
|
||||
if c.Tx.Empty() {
|
||||
return errors.ErrUnknownTxType(c.Tx)
|
||||
}
|
||||
// TODO: more checks? chainID?
|
||||
return c.Tx.ValidateBasic()
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
package base
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/go-wire/data"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk"
|
||||
"github.com/cosmos/cosmos-sdk/stack"
|
||||
)
|
||||
|
||||
func TestEncoding(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
raw := stack.NewRawTx([]byte{0x34, 0xa7})
|
||||
// raw2 := stack.NewRawTx([]byte{0x73, 0x86, 0x22})
|
||||
|
||||
cases := []struct {
|
||||
Tx sdk.Tx
|
||||
}{
|
||||
{raw},
|
||||
// {NewMultiTx(raw, raw2)},
|
||||
{NewChainTx("foobar", 0, raw)},
|
||||
}
|
||||
|
||||
for idx, tc := range cases {
|
||||
i := strconv.Itoa(idx)
|
||||
tx := tc.Tx
|
||||
|
||||
// test json in and out
|
||||
js, err := data.ToJSON(tx)
|
||||
require.Nil(err, i)
|
||||
var jtx sdk.Tx
|
||||
err = data.FromJSON(js, &jtx)
|
||||
require.Nil(err, i)
|
||||
assert.Equal(tx, jtx, i)
|
||||
|
||||
// test wire in and out
|
||||
bin, err := data.ToWire(tx)
|
||||
require.Nil(err, i)
|
||||
var wtx sdk.Tx
|
||||
err = data.FromWire(bin, &wtx)
|
||||
require.Nil(err, i)
|
||||
assert.Equal(tx, wtx, i)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
Package bonus is a temporary home for various functionalities
|
||||
that were removed for complexity, but may be added back in
|
||||
later.
|
||||
**/
|
||||
package bonus
|
|
@ -1,4 +1,4 @@
|
|||
package base
|
||||
package bonus
|
||||
|
||||
import (
|
||||
abci "github.com/tendermint/abci/types"
|
|
@ -1,4 +1,4 @@
|
|||
package base
|
||||
package bonus
|
||||
|
||||
import (
|
||||
"strings"
|
|
@ -1,12 +1,12 @@
|
|||
package base
|
||||
package bonus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
sdk "github.com/cosmos/cosmos-sdk"
|
||||
"github.com/cosmos/cosmos-sdk/stack"
|
||||
"github.com/cosmos/cosmos-sdk/state"
|
||||
"github.com/stretchr/testify/assert"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/go-wire/data"
|
||||
"github.com/tendermint/tmlibs/log"
|
|
@ -0,0 +1,73 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk"
|
||||
"github.com/cosmos/cosmos-sdk/state"
|
||||
)
|
||||
|
||||
var (
|
||||
// ChainPattern must match any valid chain_id
|
||||
ChainPattern = regexp.MustCompile("^[A-Za-z0-9_-]+$")
|
||||
)
|
||||
|
||||
// ChainedTx interface should be implemented by any
|
||||
// message to bind it to one chain, with an optional
|
||||
// expiration height
|
||||
type ChainedTx interface {
|
||||
GetChain() ChainData
|
||||
}
|
||||
|
||||
// ChainData is info from the message to bind it to
|
||||
// chain and time
|
||||
type ChainData struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
ExpiresAt uint64 `json:"expires_at"`
|
||||
}
|
||||
|
||||
// Chain enforces that this tx was bound to the named chain
|
||||
type Chain struct{}
|
||||
|
||||
var _ sdk.Decorator = Chain{}
|
||||
|
||||
// CheckTx makes sure we are on the proper chain
|
||||
// - fulfills Decorator interface
|
||||
func (c Chain) CheckTx(ctx sdk.Context, store state.SimpleDB, tx interface{}, next sdk.Checker) (res sdk.CheckResult, err error) {
|
||||
err = c.checkChainTx(ctx.ChainID(), ctx.BlockHeight(), tx)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
return next.CheckTx(ctx, store, tx)
|
||||
}
|
||||
|
||||
// DeliverTx makes sure we are on the proper chain
|
||||
// - fulfills Decorator interface
|
||||
func (c Chain) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx interface{}, next sdk.Deliverer) (res sdk.DeliverResult, err error) {
|
||||
err = c.checkChainTx(ctx.ChainID(), ctx.BlockHeight(), tx)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
return next.DeliverTx(ctx, store, tx)
|
||||
}
|
||||
|
||||
// checkChainTx makes sure the tx is a ChainedTx,
|
||||
// it is on the proper chain, and it has not expired.
|
||||
func (c Chain) checkChainTx(chainID string, height uint64, tx interface{}) error {
|
||||
// make sure it is a chaintx
|
||||
ctx, ok := tx.(ChainedTx)
|
||||
if !ok {
|
||||
return ErrNoChain()
|
||||
}
|
||||
|
||||
data := ctx.GetChain()
|
||||
|
||||
// compare against state
|
||||
if data.ChainID != chainID {
|
||||
return ErrWrongChain(data.ChainID)
|
||||
}
|
||||
if data.ExpiresAt != 0 && data.ExpiresAt <= height {
|
||||
return ErrExpired()
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package base
|
||||
package util
|
||||
|
||||
import (
|
||||
"strconv"
|
|
@ -1,5 +1,5 @@
|
|||
//nolint
|
||||
package base
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -1,4 +1,4 @@
|
|||
package base
|
||||
package util
|
||||
|
||||
import (
|
||||
"testing"
|
|
@ -0,0 +1,72 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk"
|
||||
"github.com/cosmos/cosmos-sdk/state"
|
||||
)
|
||||
|
||||
// Logger writes out log messages on every request
|
||||
type Logger struct{}
|
||||
|
||||
var _ sdk.Decorator = Logger{}
|
||||
|
||||
// CheckTx logs time and result - fulfills Middlware interface
|
||||
func (Logger) CheckTx(ctx sdk.Context, store state.SimpleDB, tx interface{}, next sdk.Checker) (res sdk.CheckResult, err error) {
|
||||
start := time.Now()
|
||||
res, err = next.CheckTx(ctx, store, tx)
|
||||
delta := time.Now().Sub(start)
|
||||
// TODO: log some info on the tx itself?
|
||||
l := ctx.With("duration", micros(delta))
|
||||
if err == nil {
|
||||
l.Debug("CheckTx", "log", res.Log)
|
||||
} else {
|
||||
l.Info("CheckTx", "err", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeliverTx logs time and result - fulfills Middlware interface
|
||||
func (Logger) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx interface{}, next sdk.Deliverer) (res sdk.DeliverResult, err error) {
|
||||
start := time.Now()
|
||||
res, err = next.DeliverTx(ctx, store, tx)
|
||||
delta := time.Now().Sub(start)
|
||||
// TODO: log some info on the tx itself?
|
||||
l := ctx.With("duration", micros(delta))
|
||||
if err == nil {
|
||||
l.Info("DeliverTx", "log", res.Log)
|
||||
} else {
|
||||
l.Error("DeliverTx", "err", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// LogTicker wraps any ticker and records the time it takes.
|
||||
// Pass in a name to be logged with this to separate out various
|
||||
// tickers
|
||||
func LogTicker(clock sdk.Ticker, name string) sdk.Ticker {
|
||||
res := func(ctx sdk.Context, s state.SimpleDB) ([]*abci.Validator, error) {
|
||||
start := time.Now()
|
||||
vals, err := clock.Tick(ctx, s)
|
||||
delta := time.Now().Sub(start)
|
||||
l := ctx.With("duration", micros(delta))
|
||||
if name != "" {
|
||||
l = l.With("name", name)
|
||||
}
|
||||
if err == nil {
|
||||
l.Info("Tock")
|
||||
} else {
|
||||
l.Error("Tock", "err", err)
|
||||
}
|
||||
return vals, err
|
||||
}
|
||||
return sdk.TickerFunc(res)
|
||||
}
|
||||
|
||||
// micros returns how many microseconds passed in a call
|
||||
func micros(d time.Duration) int {
|
||||
return int(d.Seconds() * 1000000)
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk"
|
||||
"github.com/cosmos/cosmos-sdk/errors"
|
||||
"github.com/cosmos/cosmos-sdk/state"
|
||||
)
|
||||
|
||||
// Recovery catches any panics and returns them as errors instead
|
||||
type Recovery struct{}
|
||||
|
||||
var _ sdk.Decorator = Recovery{}
|
||||
|
||||
// CheckTx catches any panic and converts to error - fulfills Middlware interface
|
||||
func (Recovery) CheckTx(ctx sdk.Context, store state.SimpleDB,
|
||||
tx interface{}, next sdk.Checker) (res sdk.CheckResult, err error) {
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = normalizePanic(r)
|
||||
}
|
||||
}()
|
||||
return next.CheckTx(ctx, store, tx)
|
||||
}
|
||||
|
||||
// DeliverTx catches any panic and converts to error - fulfills Middlware interface
|
||||
func (Recovery) DeliverTx(ctx sdk.Context, store state.SimpleDB,
|
||||
tx interface{}, next sdk.Deliverer) (res sdk.DeliverResult, err error) {
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = normalizePanic(r)
|
||||
}
|
||||
}()
|
||||
return next.DeliverTx(ctx, store, tx)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
msg := fmt.Sprintf("%v", p)
|
||||
return errors.ErrInternal(msg)
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk"
|
||||
"github.com/cosmos/cosmos-sdk/state"
|
||||
)
|
||||
|
||||
func TestRecovery(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
// generic args here...
|
||||
ctx := NewContext("test-chain", 20, log.NewNopLogger())
|
||||
store := state.NewMemKVStore()
|
||||
tx := sdk.Tx{}
|
||||
|
||||
cases := []struct {
|
||||
msg string // what to send to panic
|
||||
err error // what to send to panic
|
||||
expected string // expected text in panic
|
||||
}{
|
||||
{"buzz", nil, "buzz"},
|
||||
{"", errors.New("some text"), "some text"},
|
||||
{"text", errors.New("error"), "error"},
|
||||
}
|
||||
|
||||
for idx, tc := range cases {
|
||||
i := strconv.Itoa(idx)
|
||||
fail := PanicHandler{Msg: tc.msg, Err: tc.err}
|
||||
rec := Recovery{}
|
||||
app := New(rec).Use(fail)
|
||||
|
||||
// make sure check returns error, not a panic crash
|
||||
_, err := app.CheckTx(ctx, store, tx)
|
||||
if assert.NotNil(err, i) {
|
||||
assert.Equal(tc.expected, err.Error(), i)
|
||||
}
|
||||
|
||||
// make sure deliver returns error, not a panic crash
|
||||
_, err = app.DeliverTx(ctx, store, tx)
|
||||
if assert.NotNil(err, i) {
|
||||
assert.Equal(tc.expected, err.Error(), i)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue