cosmos-sdk/modules/coin/handler_test.go

220 lines
5.7 KiB
Go

package coin
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
crypto "github.com/tendermint/go-crypto"
"github.com/tendermint/tmlibs/log"
"github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/modules/auth"
"github.com/tendermint/basecoin/stack"
"github.com/tendermint/basecoin/state"
)
// this makes sure that txs are rejected with invalid data or permissions
func TestHandlerValidation(t *testing.T) {
assert := assert.New(t)
// these are all valid, except for minusCoins
addr1 := basecoin.Actor{App: "coin", Address: []byte{1, 2}}
addr2 := basecoin.Actor{App: "role", Address: []byte{7, 8}}
someCoins := Coins{{"atom", 123}}
doubleCoins := Coins{{"atom", 246}}
minusCoins := Coins{{"eth", -34}}
cases := []struct {
valid bool
tx basecoin.Tx
perms []basecoin.Actor
}{
// auth works with different apps
{true,
NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins)},
[]TxOutput{NewTxOutput(addr2, someCoins)}),
[]basecoin.Actor{addr1}},
{true,
NewSendTx(
[]TxInput{NewTxInput(addr2, someCoins)},
[]TxOutput{NewTxOutput(addr1, someCoins)}),
[]basecoin.Actor{addr1, addr2}},
// check multi-input with both sigs
{true,
NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins), NewTxInput(addr2, someCoins)},
[]TxOutput{NewTxOutput(addr1, doubleCoins)}),
[]basecoin.Actor{addr1, addr2}},
// wrong permissions fail
{false,
NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins)},
[]TxOutput{NewTxOutput(addr2, someCoins)}),
[]basecoin.Actor{}},
{false,
NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins)},
[]TxOutput{NewTxOutput(addr2, someCoins)}),
[]basecoin.Actor{addr2}},
{false,
NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins), NewTxInput(addr2, someCoins)},
[]TxOutput{NewTxOutput(addr1, doubleCoins)}),
[]basecoin.Actor{addr1}},
// invalid input fails
{false,
NewSendTx(
[]TxInput{NewTxInput(addr1, minusCoins)},
[]TxOutput{NewTxOutput(addr2, minusCoins)}),
[]basecoin.Actor{addr2}},
}
for i, tc := range cases {
ctx := stack.MockContext("base-chain", 100).WithPermissions(tc.perms...)
_, err := checkTx(ctx, tc.tx)
if tc.valid {
assert.Nil(err, "%d: %+v", i, err)
} else {
assert.NotNil(err, "%d", i)
}
}
}
func TestDeliverTx(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
// some sample settings
addr1 := basecoin.Actor{App: "coin", Address: []byte{1, 2}}
addr2 := basecoin.Actor{App: "role", Address: []byte{7, 8}}
addr3 := basecoin.Actor{App: "coin", Address: []byte{6, 5, 4, 3}}
someCoins := Coins{{"atom", 123}}
moreCoins := Coins{{"atom", 6487}}
diffCoins := moreCoins.Minus(someCoins)
otherCoins := Coins{{"eth", 11}}
mixedCoins := someCoins.Plus(otherCoins)
type money struct {
addr basecoin.Actor
coins Coins
}
cases := []struct {
init []money
tx basecoin.Tx
perms []basecoin.Actor
final []money // nil for error
}{
{
[]money{{addr1, moreCoins}},
NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins)},
[]TxOutput{NewTxOutput(addr2, someCoins)}),
[]basecoin.Actor{addr1},
[]money{{addr1, diffCoins}, {addr2, someCoins}},
},
// simple multi-sig 2 accounts to 1
{
[]money{{addr1, mixedCoins}, {addr2, moreCoins}},
NewSendTx(
[]TxInput{NewTxInput(addr1, otherCoins), NewTxInput(addr2, someCoins)},
[]TxOutput{NewTxOutput(addr3, mixedCoins)}),
[]basecoin.Actor{addr1, addr2},
[]money{{addr1, someCoins}, {addr2, diffCoins}, {addr3, mixedCoins}},
},
// multi-sig with one account sending many times
{
[]money{{addr1, moreCoins.Plus(otherCoins)}},
NewSendTx(
[]TxInput{NewTxInput(addr1, otherCoins), NewTxInput(addr1, someCoins)},
[]TxOutput{NewTxOutput(addr2, mixedCoins)}),
[]basecoin.Actor{addr1},
[]money{{addr1, diffCoins}, {addr2, mixedCoins}},
},
}
h := NewHandler()
for i, tc := range cases {
// setup the cases....
store := state.NewMemKVStore()
for _, m := range tc.init {
acct := Account{Coins: m.coins}
err := storeAccount(store, m.addr.Bytes(), acct)
require.Nil(err, "%d: %+v", i, err)
}
ctx := stack.MockContext("base-chain", 100).WithPermissions(tc.perms...)
_, err := h.DeliverTx(ctx, store, tc.tx)
if len(tc.final) > 0 { // valid
assert.Nil(err, "%d: %+v", i, err)
// make sure the final balances are correct
for _, f := range tc.final {
acct, err := loadAccount(store, f.addr.Bytes())
assert.Nil(err, "%d: %+v", i, err)
assert.Equal(f.coins, acct.Coins)
}
} else {
assert.NotNil(err, "%d", i)
// TODO: make sure balances unchanged!
}
}
}
func TestSetOption(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
// some sample settings
pk := crypto.GenPrivKeySecp256k1().Wrap()
addr := pk.PubKey().Address()
actor := auth.SigPerm(addr)
someCoins := Coins{{"atom", 123}}
otherCoins := Coins{{"eth", 11}}
mixedCoins := someCoins.Plus(otherCoins)
type money struct {
addr basecoin.Actor
coins Coins
}
cases := []struct {
init []GenesisAccount
expected []money
}{
{
[]GenesisAccount{{Address: addr, Balance: mixedCoins}},
[]money{{actor, mixedCoins}},
},
}
h := NewHandler()
l := log.NewNopLogger()
for i, tc := range cases {
store := state.NewMemKVStore()
key := "account"
// set the options
for j, gen := range tc.init {
value, err := json.Marshal(gen)
require.Nil(err, "%d,%d: %+v", i, j, err)
_, err = h.SetOption(l, store, NameCoin, key, string(value))
require.Nil(err)
}
// check state is proper
for _, f := range tc.expected {
acct, err := loadAccount(store, f.addr.Bytes())
assert.Nil(err, "%d: %+v", i, err)
assert.Equal(f.coins, acct.Coins)
}
}
}