Sweeping util/*
This commit is contained in:
parent
fdc7834dae
commit
6a9b8c3a92
|
@ -1,21 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
fmt.Println("vim-go")
|
|
||||||
}
|
|
||||||
|
|
||||||
type Account interface {
|
|
||||||
Get(key interface{}) (value interface{})
|
|
||||||
Address() []byte
|
|
||||||
PubKey() crypto.PubKey
|
|
||||||
|
|
||||||
// Serialize the Account to bytes.
|
|
||||||
Bytes() []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type AccountStore interface {
|
|
||||||
GetAccount(addr []byte) Account
|
|
||||||
SetAccount(acc Account)
|
|
||||||
}
|
|
197
types/coins.go
197
types/coins.go
|
@ -1,197 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Coin struct {
|
|
||||||
Denom string `json:"denom"`
|
|
||||||
Amount int64 `json:"amount"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (coin Coin) String() string {
|
|
||||||
return fmt.Sprintf("%v%v", coin.Amount, coin.Denom)
|
|
||||||
}
|
|
||||||
|
|
||||||
//regex codes for extracting coins from string
|
|
||||||
var reDenom = regexp.MustCompile("([^\\d\\W]+)")
|
|
||||||
var reAmt = regexp.MustCompile("(\\d+)")
|
|
||||||
|
|
||||||
func ParseCoin(str string) (Coin, error) {
|
|
||||||
|
|
||||||
var coin Coin
|
|
||||||
|
|
||||||
if len(str) > 0 {
|
|
||||||
amt, err := strconv.Atoi(reAmt.FindString(str))
|
|
||||||
if err != nil {
|
|
||||||
return coin, err
|
|
||||||
}
|
|
||||||
denom := reDenom.FindString(str)
|
|
||||||
coin = Coin{denom, int64(amt)}
|
|
||||||
}
|
|
||||||
|
|
||||||
return coin, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------
|
|
||||||
|
|
||||||
type Coins []Coin
|
|
||||||
|
|
||||||
func (coins Coins) String() string {
|
|
||||||
if len(coins) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
out := ""
|
|
||||||
for _, coin := range coins {
|
|
||||||
out += fmt.Sprintf("%v,", coin.String())
|
|
||||||
}
|
|
||||||
return out[:len(out)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseCoins(str string) (Coins, error) {
|
|
||||||
|
|
||||||
split := strings.Split(str, ",")
|
|
||||||
var coins []Coin
|
|
||||||
|
|
||||||
for _, el := range split {
|
|
||||||
if len(el) > 0 {
|
|
||||||
coin, err := ParseCoin(el)
|
|
||||||
if err != nil {
|
|
||||||
return coins, err
|
|
||||||
}
|
|
||||||
coins = append(coins, coin)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return coins, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must be sorted, and not have 0 amounts
|
|
||||||
func (coins Coins) IsValid() bool {
|
|
||||||
switch len(coins) {
|
|
||||||
case 0:
|
|
||||||
return true
|
|
||||||
case 1:
|
|
||||||
return coins[0].Amount != 0
|
|
||||||
default:
|
|
||||||
lowDenom := coins[0].Denom
|
|
||||||
for _, coin := range coins[1:] {
|
|
||||||
if coin.Denom <= lowDenom {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if coin.Amount == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// we compare each coin against the last denom
|
|
||||||
lowDenom = coin.Denom
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: handle empty coins!
|
|
||||||
// Currently appends an empty coin ...
|
|
||||||
func (coinsA Coins) Plus(coinsB Coins) Coins {
|
|
||||||
sum := []Coin{}
|
|
||||||
indexA, indexB := 0, 0
|
|
||||||
lenA, lenB := len(coinsA), len(coinsB)
|
|
||||||
for {
|
|
||||||
if indexA == lenA {
|
|
||||||
if indexB == lenB {
|
|
||||||
return sum
|
|
||||||
} else {
|
|
||||||
return append(sum, coinsB[indexB:]...)
|
|
||||||
}
|
|
||||||
} else if indexB == lenB {
|
|
||||||
return append(sum, coinsA[indexA:]...)
|
|
||||||
}
|
|
||||||
coinA, coinB := coinsA[indexA], coinsB[indexB]
|
|
||||||
switch strings.Compare(coinA.Denom, coinB.Denom) {
|
|
||||||
case -1:
|
|
||||||
sum = append(sum, coinA)
|
|
||||||
indexA += 1
|
|
||||||
case 0:
|
|
||||||
if coinA.Amount+coinB.Amount == 0 {
|
|
||||||
// ignore 0 sum coin type
|
|
||||||
} else {
|
|
||||||
sum = append(sum, Coin{
|
|
||||||
Denom: coinA.Denom,
|
|
||||||
Amount: coinA.Amount + coinB.Amount,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
indexA += 1
|
|
||||||
indexB += 1
|
|
||||||
case 1:
|
|
||||||
sum = append(sum, coinB)
|
|
||||||
indexB += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sum
|
|
||||||
}
|
|
||||||
|
|
||||||
func (coins Coins) Negative() Coins {
|
|
||||||
res := make([]Coin, 0, len(coins))
|
|
||||||
for _, coin := range coins {
|
|
||||||
res = append(res, Coin{
|
|
||||||
Denom: coin.Denom,
|
|
||||||
Amount: -coin.Amount,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (coinsA Coins) Minus(coinsB Coins) Coins {
|
|
||||||
return coinsA.Plus(coinsB.Negative())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (coinsA Coins) IsGTE(coinsB Coins) bool {
|
|
||||||
diff := coinsA.Minus(coinsB)
|
|
||||||
if len(diff) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return diff.IsNonnegative()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (coins Coins) IsZero() bool {
|
|
||||||
return len(coins) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (coinsA Coins) IsEqual(coinsB Coins) bool {
|
|
||||||
if len(coinsA) != len(coinsB) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i := 0; i < len(coinsA); i++ {
|
|
||||||
if coinsA[i] != coinsB[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (coins Coins) IsPositive() bool {
|
|
||||||
if len(coins) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, coinAmount := range coins {
|
|
||||||
if coinAmount.Amount <= 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (coins Coins) IsNonnegative() bool {
|
|
||||||
if len(coins) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for _, coinAmount := range coins {
|
|
||||||
if coinAmount.Amount < 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCoins(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
//Define the coins to be used in tests
|
|
||||||
good := Coins{
|
|
||||||
Coin{"GAS", 1},
|
|
||||||
Coin{"MINERAL", 1},
|
|
||||||
Coin{"TREE", 1},
|
|
||||||
}
|
|
||||||
neg := good.Negative()
|
|
||||||
sum := good.Plus(neg)
|
|
||||||
empty := Coins{
|
|
||||||
Coin{"GOLD", 0},
|
|
||||||
}
|
|
||||||
badSort1 := Coins{
|
|
||||||
Coin{"TREE", 1},
|
|
||||||
Coin{"GAS", 1},
|
|
||||||
Coin{"MINERAL", 1},
|
|
||||||
}
|
|
||||||
badSort2 := Coins{ // both are after the first one, but the second and third are in the wrong order
|
|
||||||
Coin{"GAS", 1},
|
|
||||||
Coin{"TREE", 1},
|
|
||||||
Coin{"MINERAL", 1},
|
|
||||||
}
|
|
||||||
badAmt := Coins{
|
|
||||||
Coin{"GAS", 1},
|
|
||||||
Coin{"TREE", 0},
|
|
||||||
Coin{"MINERAL", 1},
|
|
||||||
}
|
|
||||||
dup := Coins{
|
|
||||||
Coin{"GAS", 1},
|
|
||||||
Coin{"GAS", 1},
|
|
||||||
Coin{"MINERAL", 1},
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.True(good.IsValid(), "Coins are valid")
|
|
||||||
assert.True(good.IsPositive(), "Expected coins to be positive: %v", good)
|
|
||||||
assert.True(good.IsGTE(empty), "Expected %v to be >= %v", good, empty)
|
|
||||||
assert.False(neg.IsPositive(), "Expected neg coins to not be positive: %v", neg)
|
|
||||||
assert.Zero(len(sum), "Expected 0 coins")
|
|
||||||
assert.False(badSort1.IsValid(), "Coins are not sorted")
|
|
||||||
assert.False(badSort2.IsValid(), "Coins are not sorted")
|
|
||||||
assert.False(badAmt.IsValid(), "Coins cannot include 0 amounts")
|
|
||||||
assert.False(dup.IsValid(), "Duplicate coin")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//Test the parse coin and parse coins functionality
|
|
||||||
func TestParse(t *testing.T) {
|
|
||||||
assert, require := assert.New(t), require.New(t)
|
|
||||||
|
|
||||||
makeCoin := func(str string) Coin {
|
|
||||||
coin, err := ParseCoin(str)
|
|
||||||
require.Nil(err)
|
|
||||||
return coin
|
|
||||||
}
|
|
||||||
|
|
||||||
makeCoins := func(str string) Coins {
|
|
||||||
coin, err := ParseCoins(str)
|
|
||||||
require.Nil(err)
|
|
||||||
return coin
|
|
||||||
}
|
|
||||||
|
|
||||||
//testing ParseCoin Function
|
|
||||||
assert.Equal(Coin{}, makeCoin(""), "ParseCoin makes bad empty coin")
|
|
||||||
assert.Equal(Coin{"fooCoin", 1}, makeCoin("1fooCoin"), "ParseCoin makes bad coins")
|
|
||||||
assert.Equal(Coin{"barCoin", 10}, makeCoin("10 barCoin"), "ParseCoin makes bad coins")
|
|
||||||
|
|
||||||
//testing ParseCoins Function
|
|
||||||
assert.True(Coins{{"fooCoin", 1}}.IsEqual(makeCoins("1fooCoin")),
|
|
||||||
"ParseCoins doesn't parse a single coin")
|
|
||||||
assert.True(Coins{{"barCoin", 99}, {"fooCoin", 1}}.IsEqual(makeCoins("99barCoin,1fooCoin")),
|
|
||||||
"ParseCoins doesn't properly parse two coins")
|
|
||||||
assert.True(Coins{{"barCoin", 99}, {"fooCoin", 1}}.IsEqual(makeCoins("99 barCoin, 1 fooCoin")),
|
|
||||||
"ParseCoins doesn't properly parse two coins which use spaces")
|
|
||||||
}
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
tm "github.com/tendermint/tendermint/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
NOTE: Golang's Context is embedded and relied on
|
||||||
|
for compatibility w/ tools like monkit.
|
||||||
|
(https://github.com/spacemonkeygo/monkit)
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
defer mon.Task()(&ctx.Context)(&err)
|
||||||
|
|
||||||
|
*/
|
||||||
|
type SDKContext struct {
|
||||||
|
context.Context
|
||||||
|
// NOTE: adding fields here will break monkit compatibility
|
||||||
|
// use context.Context instead if possible.
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSDKContext(header tm.Header) SDKContext {
|
||||||
|
c := SDKContext{
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
c = c.setBlockHeader(header)
|
||||||
|
c = c.setBlockHeight(int64(header.Height))
|
||||||
|
c = c.setChainID(header.ChainID)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c SDKContext) WithValueSDK(key interface{}, value interface{}) SDKContext {
|
||||||
|
return SDKContext{
|
||||||
|
Context: context.WithValue(c.Context, key, value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c SDKContext) WithValue(key interface{}, value interface{}) Context {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------
|
||||||
|
// Our extensions
|
||||||
|
|
||||||
|
type contextKey int // local to the context module
|
||||||
|
|
||||||
|
const (
|
||||||
|
contextKeyBlockHeader contextKey = iota
|
||||||
|
contextKeyBlockHeight
|
||||||
|
contextKeyChainID
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c SDKContext) BlockHeader() tm.Header {
|
||||||
|
return c.Value(contextKeyBlockHeader).(tm.Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unexposed to prevent overriding.
|
||||||
|
func (c SDKContext) setBlockHeader(header tm.Header) SDKContext {
|
||||||
|
return c.WithValueSDK(contextKeyBlockHeader, header)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unexposed to prevent overriding.
|
||||||
|
func (c SDKContext) setBlockHeight(height int64) SDKContext {
|
||||||
|
return c.WithValueSDK(contextKeyBlockHeight, header)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unexposed to prevent overriding.
|
||||||
|
func (c SDKContext) setChainID(chainID string) SDKContext {
|
||||||
|
return c.WithValueSDK(contextKeyChainID, header)
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import "github.com/tendermint/tmlibs/crypto"
|
import crypto "github.com/tendermint/go-crypto"
|
||||||
|
|
||||||
// The parsed tx bytes is called a Msg.
|
// The parsed tx bytes is called a Msg.
|
||||||
type Msg interface {
|
type Msg interface {
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
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 sdk.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 sdk.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,92 +0,0 @@
|
||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk"
|
|
||||||
"github.com/cosmos/cosmos-sdk/state"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewChainTx(name string, height uint64, data []byte) ChainedTx {
|
|
||||||
return chainTx{
|
|
||||||
ChainData: ChainData{name, height},
|
|
||||||
Data: data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type chainTx struct {
|
|
||||||
ChainData
|
|
||||||
Data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c chainTx) GetChain() ChainData {
|
|
||||||
return c.ChainData
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c chainTx) GetTx() interface{} {
|
|
||||||
return RawTx{c.Data}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestChain(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
msg := "got it"
|
|
||||||
chainID := "my-chain"
|
|
||||||
height := uint64(100)
|
|
||||||
|
|
||||||
raw := []byte{1, 2, 3, 4}
|
|
||||||
cases := []struct {
|
|
||||||
tx interface{}
|
|
||||||
valid bool
|
|
||||||
errorMsg string
|
|
||||||
}{
|
|
||||||
// check the chain ids are validated
|
|
||||||
{NewChainTx(chainID, 0, raw), true, ""},
|
|
||||||
// non-matching chainid, or impossible chain id
|
|
||||||
{NewChainTx("someone-else", 0, raw), false, "someone-else: Wrong chain"},
|
|
||||||
{NewChainTx("Inval$$d:CH%%n", 0, raw), false, "Wrong chain"},
|
|
||||||
// Wrong tx type
|
|
||||||
{raw, false, "No chain id provided"},
|
|
||||||
// Check different heights - must be 0 or higher than current height
|
|
||||||
{NewChainTx(chainID, height+1, raw), true, ""},
|
|
||||||
{NewChainTx(chainID, height, raw), false, "Tx expired"},
|
|
||||||
{NewChainTx(chainID, 1, raw), false, "expired"},
|
|
||||||
{NewChainTx(chainID, 0, raw), true, ""},
|
|
||||||
}
|
|
||||||
|
|
||||||
// generic args here...
|
|
||||||
ctx := MockContext(chainID, height)
|
|
||||||
store := state.NewMemKVStore()
|
|
||||||
|
|
||||||
// build the stack
|
|
||||||
ok := OKHandler{Log: msg}
|
|
||||||
app := sdk.ChainDecorators(Chain{}).WithHandler(ok)
|
|
||||||
|
|
||||||
for idx, tc := range cases {
|
|
||||||
i := strconv.Itoa(idx)
|
|
||||||
|
|
||||||
// make sure check returns error, not a panic crash
|
|
||||||
cres, err := app.CheckTx(ctx, store, tc.tx)
|
|
||||||
if tc.valid {
|
|
||||||
assert.Nil(err, "%d: %+v", idx, err)
|
|
||||||
assert.Equal(msg, cres.Log, i)
|
|
||||||
} else {
|
|
||||||
if assert.NotNil(err, i) {
|
|
||||||
assert.Contains(err.Error(), tc.errorMsg, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure deliver returns error, not a panic crash
|
|
||||||
dres, err := app.DeliverTx(ctx, store, tc.tx)
|
|
||||||
if tc.valid {
|
|
||||||
assert.Nil(err, "%d: %+v", idx, err)
|
|
||||||
assert.Equal(msg, dres.Log, i)
|
|
||||||
} else {
|
|
||||||
if assert.NotNil(err, i) {
|
|
||||||
assert.Contains(err.Error(), tc.errorMsg, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package commands
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk"
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/commands"
|
|
||||||
txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs"
|
|
||||||
"github.com/cosmos/cosmos-sdk/modules/base"
|
|
||||||
)
|
|
||||||
|
|
||||||
//nolint
|
|
||||||
const (
|
|
||||||
FlagExpires = "expires"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ChainWrapper wraps a tx with an chain info and optional expiration
|
|
||||||
type ChainWrapper struct{}
|
|
||||||
|
|
||||||
var _ txcmd.Wrapper = ChainWrapper{}
|
|
||||||
|
|
||||||
// Wrap will wrap the tx with a ChainTx from the standard flags
|
|
||||||
func (ChainWrapper) Wrap(tx sdk.Tx) (res sdk.Tx, err error) {
|
|
||||||
expires := viper.GetInt64(FlagExpires)
|
|
||||||
chain := commands.GetChainID()
|
|
||||||
if chain == "" {
|
|
||||||
return res, errors.New("No chain-id provided")
|
|
||||||
}
|
|
||||||
res = base.NewChainTx(chain, uint64(expires), tx)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register adds the sequence flags to the cli
|
|
||||||
func (ChainWrapper) Register(fs *pflag.FlagSet) {
|
|
||||||
fs.Uint64(FlagExpires, 0, "Block height at which this tx expires")
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk"
|
|
||||||
"github.com/cosmos/cosmos-sdk/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CheckDecorator returns an error if the tx doesn't have auth of this
|
|
||||||
// Required Actor, otherwise passes along the call untouched
|
|
||||||
type CheckDecorator struct {
|
|
||||||
Required sdk.Actor
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ sdk.Decorator = CheckDecorator{}
|
|
||||||
|
|
||||||
func (p CheckDecorator) CheckTx(ctx sdk.Context, store sdk.SimpleDB,
|
|
||||||
tx interface{}, next sdk.Checker) (res sdk.CheckResult, err error) {
|
|
||||||
|
|
||||||
if !ctx.HasPermission(p.Required) {
|
|
||||||
return res, errors.ErrUnauthorized()
|
|
||||||
}
|
|
||||||
return next.CheckTx(ctx, store, tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p CheckDecorator) DeliverTx(ctx sdk.Context, store sdk.SimpleDB,
|
|
||||||
tx interface{}, next sdk.Deliverer) (res sdk.DeliverResult, err error) {
|
|
||||||
|
|
||||||
if !ctx.HasPermission(p.Required) {
|
|
||||||
return res, errors.ErrUnauthorized()
|
|
||||||
}
|
|
||||||
return next.DeliverTx(ctx, store, tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GrantDecorator tries to set the permission to this Actor, which may be prohibited
|
|
||||||
type GrantDecorator struct {
|
|
||||||
Auth sdk.Actor
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ sdk.Decorator = GrantDecorator{}
|
|
||||||
|
|
||||||
func (g GrantDecorator) CheckTx(ctx sdk.Context, store sdk.SimpleDB,
|
|
||||||
tx interface{}, next sdk.Checker) (res sdk.CheckResult, err error) {
|
|
||||||
|
|
||||||
ctx = ctx.WithPermissions(g.Auth)
|
|
||||||
return next.CheckTx(ctx, store, tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g GrantDecorator) DeliverTx(ctx sdk.Context, store sdk.SimpleDB,
|
|
||||||
tx interface{}, next sdk.Deliverer) (res sdk.DeliverResult, err error) {
|
|
||||||
|
|
||||||
ctx = ctx.WithPermissions(g.Auth)
|
|
||||||
return next.DeliverTx(ctx, store, tx)
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
/**
|
|
||||||
Package util contains various utility handlers, decorators,
|
|
||||||
and test helpers that can be use by many modules and applications.
|
|
||||||
**/
|
|
||||||
package util
|
|
|
@ -1,37 +0,0 @@
|
||||||
//nolint
|
|
||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errNoChain = fmt.Errorf("No chain id provided") //move base
|
|
||||||
errWrongChain = fmt.Errorf("Wrong chain for tx") //move base
|
|
||||||
errExpired = fmt.Errorf("Tx expired") //move base
|
|
||||||
|
|
||||||
unauthorized = abci.CodeType_Unauthorized
|
|
||||||
)
|
|
||||||
|
|
||||||
func ErrNoChain() errors.TMError {
|
|
||||||
return errors.WithCode(errNoChain, unauthorized)
|
|
||||||
}
|
|
||||||
func IsNoChainErr(err error) bool {
|
|
||||||
return errors.IsSameError(errNoChain, err)
|
|
||||||
}
|
|
||||||
func ErrWrongChain(chain string) errors.TMError {
|
|
||||||
return errors.WithMessage(chain, errWrongChain, unauthorized)
|
|
||||||
}
|
|
||||||
func IsWrongChainErr(err error) bool {
|
|
||||||
return errors.IsSameError(errWrongChain, err)
|
|
||||||
}
|
|
||||||
func ErrExpired() errors.TMError {
|
|
||||||
return errors.WithCode(errExpired, unauthorized)
|
|
||||||
}
|
|
||||||
func IsExpiredErr(err error) bool {
|
|
||||||
return errors.IsSameError(errExpired, err)
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestErrorMatches(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
cases := []struct {
|
|
||||||
pattern, err error
|
|
||||||
match bool
|
|
||||||
}{
|
|
||||||
{errWrongChain, ErrWrongChain("hakz"), true},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range cases {
|
|
||||||
same := errors.IsSameError(tc.pattern, tc.err)
|
|
||||||
assert.Equal(tc.match, same, "%d: %#v / %#v", i, tc.pattern, tc.err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestChecks(t *testing.T) {
|
|
||||||
// TODO: make sure the Is and Err methods match
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
cases := []struct {
|
|
||||||
err error
|
|
||||||
check func(error) bool
|
|
||||||
match bool
|
|
||||||
}{
|
|
||||||
// make sure WrongChain works properly
|
|
||||||
{ErrWrongChain("fooz"), errors.IsUnauthorizedErr, true},
|
|
||||||
{ErrWrongChain("barz"), IsWrongChainErr, true},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range cases {
|
|
||||||
match := tc.check(tc.err)
|
|
||||||
assert.Equal(tc.match, match, "%d", i)
|
|
||||||
}
|
|
||||||
}
|
|
131
util/helpers.go
131
util/helpers.go
|
@ -1,131 +0,0 @@
|
||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/tendermint/go-wire/data"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk"
|
|
||||||
"github.com/cosmos/cosmos-sdk/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
//nolint
|
|
||||||
const (
|
|
||||||
// ByteRawTx = 0xF0
|
|
||||||
// ByteCheckTx = 0xF1
|
|
||||||
// ByteFailTx = 0xF2
|
|
||||||
|
|
||||||
// TypeRawTx = NameOK + "/raw" // this will just say a-ok to RawTx
|
|
||||||
// TypeCheckTx = NameCheck + "/tx"
|
|
||||||
// TypeFailTx = NameFail + "/tx"
|
|
||||||
|
|
||||||
rawMaxSize = 2000 * 1000
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// sdk.TxMapper.
|
|
||||||
// RegisterImplementation(RawTx{}, TypeRawTx, ByteRawTx).
|
|
||||||
// RegisterImplementation(CheckTx{}, TypeCheckTx, ByteCheckTx).
|
|
||||||
// RegisterImplementation(FailTx{}, TypeFailTx, ByteFailTx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RawTx just contains bytes that can be hex-ified
|
|
||||||
type RawTx struct {
|
|
||||||
Data data.Bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRawTx creates a RawTx object
|
|
||||||
func NewRawTx(data []byte) RawTx {
|
|
||||||
return RawTx{Data: data}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateBasic can ensure a limited size of tx
|
|
||||||
func (r RawTx) ValidateBasic() error {
|
|
||||||
if len(r.Data) > rawMaxSize {
|
|
||||||
return errors.ErrTooLarge()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OKHandler just used to return okay to everything
|
|
||||||
type OKHandler struct {
|
|
||||||
Log string
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ sdk.Handler = OKHandler{}
|
|
||||||
|
|
||||||
// CheckTx always returns an empty success tx
|
|
||||||
func (ok OKHandler) CheckTx(ctx sdk.Context, store sdk.SimpleDB,
|
|
||||||
tx interface{}) (res sdk.CheckResult, err error) {
|
|
||||||
return sdk.CheckResult{Log: ok.Log}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeliverTx always returns an empty success tx
|
|
||||||
func (ok OKHandler) DeliverTx(ctx sdk.Context, store sdk.SimpleDB,
|
|
||||||
tx interface{}) (res sdk.DeliverResult, err error) {
|
|
||||||
return sdk.DeliverResult{Log: ok.Log}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EchoHandler returns success, echoing res.Data = tx bytes
|
|
||||||
type EchoHandler struct{}
|
|
||||||
|
|
||||||
var _ sdk.Handler = EchoHandler{}
|
|
||||||
|
|
||||||
// CheckTx returns input if RawTx comes in, otherwise panic
|
|
||||||
func (EchoHandler) CheckTx(ctx sdk.Context, store sdk.SimpleDB,
|
|
||||||
msg interface{}) (res sdk.CheckResult, err error) {
|
|
||||||
raw := sdk.MustGetTx(msg).(RawTx)
|
|
||||||
return sdk.CheckResult{Data: raw.Data}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeliverTx returns input if RawTx comes in, otherwise panic
|
|
||||||
func (EchoHandler) DeliverTx(ctx sdk.Context, store sdk.SimpleDB,
|
|
||||||
msg interface{}) (res sdk.DeliverResult, err error) {
|
|
||||||
raw := sdk.MustGetTx(msg).(RawTx)
|
|
||||||
return sdk.DeliverResult{Data: raw.Data}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FailHandler always returns an error
|
|
||||||
type FailHandler struct {
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ sdk.Handler = FailHandler{}
|
|
||||||
|
|
||||||
// CheckTx always returns the given error
|
|
||||||
func (f FailHandler) CheckTx(ctx sdk.Context, store sdk.SimpleDB,
|
|
||||||
tx interface{}) (res sdk.CheckResult, err error) {
|
|
||||||
return res, errors.Wrap(f.Err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeliverTx always returns the given error
|
|
||||||
func (f FailHandler) DeliverTx(ctx sdk.Context, store sdk.SimpleDB,
|
|
||||||
tx interface{}) (res sdk.DeliverResult, err error) {
|
|
||||||
return res, errors.Wrap(f.Err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PanicHandler always panics, using the given error (first choice) or msg (fallback)
|
|
||||||
type PanicHandler struct {
|
|
||||||
Msg string
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ sdk.Handler = PanicHandler{}
|
|
||||||
|
|
||||||
// CheckTx always panics
|
|
||||||
func (p PanicHandler) CheckTx(ctx sdk.Context, store sdk.SimpleDB,
|
|
||||||
tx interface{}) (res sdk.CheckResult, err error) {
|
|
||||||
|
|
||||||
if p.Err != nil {
|
|
||||||
panic(p.Err)
|
|
||||||
}
|
|
||||||
panic(p.Msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeliverTx always panics
|
|
||||||
func (p PanicHandler) DeliverTx(ctx sdk.Context, store sdk.SimpleDB,
|
|
||||||
tx interface{}) (res sdk.DeliverResult, err error) {
|
|
||||||
|
|
||||||
if p.Err != nil {
|
|
||||||
panic(p.Err)
|
|
||||||
}
|
|
||||||
panic(p.Msg)
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk"
|
|
||||||
"github.com/cosmos/cosmos-sdk/state"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestOK(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
ctx := MockContext("test-chain", 20)
|
|
||||||
store := state.NewMemKVStore()
|
|
||||||
data := "this looks okay"
|
|
||||||
tx := sdk.Tx{}
|
|
||||||
|
|
||||||
ok := OKHandler{Log: data}
|
|
||||||
res, err := ok.CheckTx(ctx, store, tx)
|
|
||||||
assert.Nil(err, "%+v", err)
|
|
||||||
assert.Equal(data, res.Log)
|
|
||||||
|
|
||||||
dres, err := ok.DeliverTx(ctx, store, tx)
|
|
||||||
assert.Nil(err, "%+v", err)
|
|
||||||
assert.Equal(data, dres.Log)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFail(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
ctx := MockContext("test-chain", 20)
|
|
||||||
store := state.NewMemKVStore()
|
|
||||||
msg := "big problem"
|
|
||||||
tx := sdk.Tx{}
|
|
||||||
|
|
||||||
fail := FailHandler{Err: errors.New(msg)}
|
|
||||||
_, err := fail.CheckTx(ctx, store, tx)
|
|
||||||
if assert.NotNil(err) {
|
|
||||||
assert.Equal(msg, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = fail.DeliverTx(ctx, store, tx)
|
|
||||||
if assert.NotNil(err) {
|
|
||||||
assert.Equal(msg, err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPanic(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
ctx := MockContext("test-chain", 20)
|
|
||||||
store := state.NewMemKVStore()
|
|
||||||
msg := "system crash!"
|
|
||||||
tx := sdk.Tx{}
|
|
||||||
|
|
||||||
fail := PanicHandler{Msg: msg}
|
|
||||||
assert.Panics(func() { fail.CheckTx(ctx, store, tx) })
|
|
||||||
assert.Panics(func() { fail.DeliverTx(ctx, store, tx) })
|
|
||||||
}
|
|
93
util/mock.go
93
util/mock.go
|
@ -1,93 +0,0 @@
|
||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
|
|
||||||
"github.com/tendermint/tmlibs/log"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk"
|
|
||||||
)
|
|
||||||
|
|
||||||
// store nonce as it's own type so no one can even try to fake it
|
|
||||||
type nonce int64
|
|
||||||
|
|
||||||
type naiveContext struct {
|
|
||||||
id nonce
|
|
||||||
chain string
|
|
||||||
height uint64
|
|
||||||
perms []sdk.Actor
|
|
||||||
log.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockContext returns a simple, non-checking context for test cases.
|
|
||||||
//
|
|
||||||
// Always use NewContext() for production code to sandbox malicious code better
|
|
||||||
func MockContext(chain string, height uint64) sdk.Context {
|
|
||||||
return naiveContext{
|
|
||||||
id: nonce(rand.Int63()),
|
|
||||||
chain: chain,
|
|
||||||
height: height,
|
|
||||||
Logger: log.NewNopLogger(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ sdk.Context = naiveContext{}
|
|
||||||
|
|
||||||
func (c naiveContext) ChainID() string {
|
|
||||||
return c.chain
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c naiveContext) BlockHeight() uint64 {
|
|
||||||
return c.height
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithPermissions will panic if they try to set permission without the proper app
|
|
||||||
func (c naiveContext) WithPermissions(perms ...sdk.Actor) sdk.Context {
|
|
||||||
return naiveContext{
|
|
||||||
id: c.id,
|
|
||||||
chain: c.chain,
|
|
||||||
height: c.height,
|
|
||||||
perms: append(c.perms, perms...),
|
|
||||||
Logger: c.Logger,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c naiveContext) HasPermission(perm sdk.Actor) bool {
|
|
||||||
for _, p := range c.perms {
|
|
||||||
if p.Equals(perm) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c naiveContext) GetPermissions(chain, app string) (res []sdk.Actor) {
|
|
||||||
for _, p := range c.perms {
|
|
||||||
if chain == p.ChainID {
|
|
||||||
if app == "" || app == p.App {
|
|
||||||
res = append(res, p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsParent ensures that this is derived from the given secureClient
|
|
||||||
func (c naiveContext) IsParent(other sdk.Context) bool {
|
|
||||||
nc, ok := other.(naiveContext)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return c.id == nc.id
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset should clear out all permissions,
|
|
||||||
// but carry on knowledge that this is a child
|
|
||||||
func (c naiveContext) Reset() sdk.Context {
|
|
||||||
return naiveContext{
|
|
||||||
id: c.id,
|
|
||||||
chain: c.chain,
|
|
||||||
height: c.height,
|
|
||||||
Logger: c.Logger,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
package util
|
|
||||||
|
|
||||||
// PrefixedKey returns the absolute path to a given key in a particular
|
|
||||||
// app's state-space
|
|
||||||
//
|
|
||||||
// This is useful for to set up queries for this particular app data
|
|
||||||
func PrefixedKey(app string, key []byte) []byte {
|
|
||||||
prefix := append([]byte(app), byte(0))
|
|
||||||
return append(prefix, key...)
|
|
||||||
}
|
|
Loading…
Reference in New Issue