Moved Coins from types -> modules/coin
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
package coin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Coin hold some amount of one currency
|
||||
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("")
|
||||
var reAmt = regexp.MustCompile("(\\d+)")
|
||||
|
||||
var reCoin = regexp.MustCompile("^([[:digit:]]+)[[:space:]]*([[:alpha:]]+)$")
|
||||
|
||||
// ParseCoin parses a cli input for one coin type, returning errors if invalid.
|
||||
// This returns an error on an empty string as well.
|
||||
func ParseCoin(str string) (Coin, error) {
|
||||
var coin Coin
|
||||
|
||||
matches := reCoin.FindStringSubmatch(strings.TrimSpace(str))
|
||||
if matches == nil {
|
||||
return coin, errors.Errorf("%s is invalid coin definition", str)
|
||||
}
|
||||
|
||||
// parse the amount (should always parse properly)
|
||||
amt, err := strconv.Atoi(matches[1])
|
||||
if err != nil {
|
||||
return coin, err
|
||||
}
|
||||
|
||||
coin = Coin{matches[2], int64(amt)}
|
||||
return coin, nil
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// Coins is a set of Coin, one per currency
|
||||
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]
|
||||
}
|
||||
|
||||
// ParseCoins will parse out a list of coins separated by commas.
|
||||
// If nothing is provided, it returns an empty array
|
||||
func ParseCoins(str string) (Coins, error) {
|
||||
// empty string is empty list...
|
||||
if len(str) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
split := strings.Split(str, ",")
|
||||
var coins Coins
|
||||
|
||||
for _, el := range split {
|
||||
coin, err := ParseCoin(el)
|
||||
if err != nil {
|
||||
return coins, err
|
||||
}
|
||||
coins = append(coins, coin)
|
||||
}
|
||||
|
||||
// ensure they are in proper order, to avoid random failures later
|
||||
coins.Sort()
|
||||
if !coins.IsValid() {
|
||||
return nil, errors.Errorf("ParseCoins invalid: %#v", coins)
|
||||
}
|
||||
|
||||
return coins, nil
|
||||
}
|
||||
|
||||
// IsValid asserts the Coins are sorted, and don't 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
|
||||
}
|
||||
}
|
||||
|
||||
// Plus combines to sets of coins
|
||||
//
|
||||
// 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
|
||||
}
|
||||
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++
|
||||
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++
|
||||
indexB++
|
||||
case 1:
|
||||
sum = append(sum, coinB)
|
||||
indexB++
|
||||
}
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// Negative returns a set of coins with all amount negative
|
||||
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
|
||||
}
|
||||
|
||||
// Minus subtracts a set of coins from another (adds the inverse)
|
||||
func (coinsA Coins) Minus(coinsB Coins) Coins {
|
||||
return coinsA.Plus(coinsB.Negative())
|
||||
}
|
||||
|
||||
// IsGTE returns True iff coinsA is NonNegative(), and for every
|
||||
// currency in coinsB, the currency is present at an equal or greater
|
||||
// amount in coinsB
|
||||
func (coinsA Coins) IsGTE(coinsB Coins) bool {
|
||||
diff := coinsA.Minus(coinsB)
|
||||
if len(diff) == 0 {
|
||||
return true
|
||||
}
|
||||
return diff.IsNonnegative()
|
||||
}
|
||||
|
||||
// IsZero returns true if there are no coins
|
||||
func (coins Coins) IsZero() bool {
|
||||
return len(coins) == 0
|
||||
}
|
||||
|
||||
// IsEqual returns true if the two sets of Coins have the same value
|
||||
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
|
||||
}
|
||||
|
||||
// IsPositive returns true if there is at least one coin, and all
|
||||
// currencies have a positive value
|
||||
func (coins Coins) IsPositive() bool {
|
||||
if len(coins) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, coinAmount := range coins {
|
||||
if coinAmount.Amount <= 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsNonnegative returns true if there is no currency with a negative value
|
||||
// (even no coins is true here)
|
||||
func (coins Coins) IsNonnegative() bool {
|
||||
if len(coins) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, coinAmount := range coins {
|
||||
if coinAmount.Amount < 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/*** Implement Sort interface ***/
|
||||
|
||||
//nolint
|
||||
func (coins Coins) Len() int { return len(coins) }
|
||||
func (coins Coins) Less(i, j int) bool { return coins[i].Denom < coins[j].Denom }
|
||||
func (coins Coins) Swap(i, j int) { coins[i], coins[j] = coins[j], coins[i] }
|
||||
|
||||
var _ sort.Interface = Coins{}
|
||||
|
||||
// Sort is a helper function to sort the set of coins inplace
|
||||
func (coins Coins) Sort() { sort.Sort(coins) }
|
||||
@@ -0,0 +1,139 @@
|
||||
package coin
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
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 := assert.New(t)
|
||||
|
||||
cases := []struct {
|
||||
input string
|
||||
valid bool // if false, we expect an error on parse
|
||||
expected Coins // if valid is true, make sure this is returned
|
||||
}{
|
||||
{"", true, nil},
|
||||
{"1foo", true, Coins{{"foo", 1}}},
|
||||
{"10bar", true, Coins{{"bar", 10}}},
|
||||
{"99bar,1foo", true, Coins{{"bar", 99}, {"foo", 1}}},
|
||||
{"98 bar , 1 foo ", true, Coins{{"bar", 98}, {"foo", 1}}},
|
||||
{" 55\t \t bling\n", true, Coins{{"bling", 55}}},
|
||||
{"2foo, 97 bar", true, Coins{{"bar", 97}, {"foo", 2}}},
|
||||
{"5 mycoin,", false, nil}, // no empty coins in a list
|
||||
{"2 3foo, 97 bar", false, nil}, // 3foo is invalid coin name
|
||||
{"11me coin, 12you coin", false, nil}, // no spaces in coin names
|
||||
{"1.2btc", false, nil}, // amount must be integer
|
||||
{"5foo-bar", false, nil}, // once more, only letters in coin name
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
res, err := ParseCoins(tc.input)
|
||||
if !tc.valid {
|
||||
assert.NotNil(err, "%s: %#v", tc.input, res)
|
||||
} else if assert.Nil(err, "%s: %+v", tc.input, err) {
|
||||
assert.Equal(tc.expected, res)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSortCoins(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
good := Coins{
|
||||
Coin{"GAS", 1},
|
||||
Coin{"MINERAL", 1},
|
||||
Coin{"TREE", 1},
|
||||
}
|
||||
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},
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
coins Coins
|
||||
before, after bool // valid before/after sort
|
||||
}{
|
||||
{good, true, true},
|
||||
{empty, false, false},
|
||||
{badSort1, false, true},
|
||||
{badSort2, false, true},
|
||||
{badAmt, false, false},
|
||||
{dup, false, false},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
assert.Equal(tc.before, tc.coins.IsValid())
|
||||
tc.coins.Sort()
|
||||
assert.Equal(tc.after, tc.coins.IsValid())
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,6 @@ import (
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/go-wire/data"
|
||||
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
|
||||
/**** code to parse accounts from genesis docs ***/
|
||||
@@ -19,7 +17,7 @@ type GenesisAccount struct {
|
||||
// this from types.Account (don't know how to embed this properly)
|
||||
PubKey crypto.PubKey `json:"pub_key"` // May be nil, if not known.
|
||||
Sequence int `json:"sequence"`
|
||||
Balance types.Coins `json:"coins"`
|
||||
Balance Coins `json:"coins"`
|
||||
}
|
||||
|
||||
// ToAccount - GenesisAccount struct to a basecoin Account
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/stack"
|
||||
"github.com/tendermint/basecoin/state"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
|
||||
// this makes sure that txs are rejected with invalid data or permissions
|
||||
@@ -23,9 +22,9 @@ func TestHandlerValidation(t *testing.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 := types.Coins{{"atom", 123}}
|
||||
doubleCoins := types.Coins{{"atom", 246}}
|
||||
minusCoins := types.Coins{{"eth", -34}}
|
||||
someCoins := Coins{{"atom", 123}}
|
||||
doubleCoins := Coins{{"atom", 246}}
|
||||
minusCoins := Coins{{"eth", -34}}
|
||||
|
||||
cases := []struct {
|
||||
valid bool
|
||||
@@ -93,15 +92,15 @@ func TestDeliverTx(t *testing.T) {
|
||||
addr2 := basecoin.Actor{App: "role", Address: []byte{7, 8}}
|
||||
addr3 := basecoin.Actor{App: "coin", Address: []byte{6, 5, 4, 3}}
|
||||
|
||||
someCoins := types.Coins{{"atom", 123}}
|
||||
moreCoins := types.Coins{{"atom", 6487}}
|
||||
someCoins := Coins{{"atom", 123}}
|
||||
moreCoins := Coins{{"atom", 6487}}
|
||||
diffCoins := moreCoins.Minus(someCoins)
|
||||
otherCoins := types.Coins{{"eth", 11}}
|
||||
otherCoins := Coins{{"eth", 11}}
|
||||
mixedCoins := someCoins.Plus(otherCoins)
|
||||
|
||||
type money struct {
|
||||
addr basecoin.Actor
|
||||
coins types.Coins
|
||||
coins Coins
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
@@ -175,13 +174,13 @@ func TestSetOption(t *testing.T) {
|
||||
addr := pk.PubKey().Address()
|
||||
actor := basecoin.Actor{App: stack.NameSigs, Address: addr}
|
||||
|
||||
someCoins := types.Coins{{"atom", 123}}
|
||||
otherCoins := types.Coins{{"eth", 11}}
|
||||
someCoins := Coins{{"atom", 123}}
|
||||
otherCoins := Coins{{"eth", 11}}
|
||||
mixedCoins := someCoins.Plus(otherCoins)
|
||||
|
||||
type money struct {
|
||||
addr basecoin.Actor
|
||||
coins types.Coins
|
||||
coins Coins
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package coin
|
||||
|
||||
import (
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/stack"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/go-wire/data"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/stack"
|
||||
)
|
||||
|
||||
// AccountWithKey is a helper for tests, that includes and account
|
||||
@@ -17,7 +17,7 @@ type AccountWithKey struct {
|
||||
|
||||
// NewAccountWithKey creates an account with the given balance
|
||||
// and a random private key
|
||||
func NewAccountWithKey(coins types.Coins) *AccountWithKey {
|
||||
func NewAccountWithKey(coins Coins) *AccountWithKey {
|
||||
return &AccountWithKey{
|
||||
Key: crypto.GenPrivKeyEd25519().Wrap(),
|
||||
Account: Account{Coins: coins},
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
"github.com/tendermint/basecoin/state"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
|
||||
// Accountant - custom object to manage coins for the coin module
|
||||
@@ -39,13 +38,13 @@ func (a Accountant) GetAccount(store state.KVStore, addr basecoin.Actor) (Accoun
|
||||
}
|
||||
|
||||
// CheckCoins makes sure there are funds, but doesn't change anything
|
||||
func (a Accountant) CheckCoins(store state.KVStore, addr basecoin.Actor, coins types.Coins, seq int) (types.Coins, error) {
|
||||
func (a Accountant) CheckCoins(store state.KVStore, addr basecoin.Actor, coins Coins, seq int) (Coins, error) {
|
||||
acct, err := a.updateCoins(store, addr, coins, seq)
|
||||
return acct.Coins, err
|
||||
}
|
||||
|
||||
// ChangeCoins changes the money, returns error if it would be negative
|
||||
func (a Accountant) ChangeCoins(store state.KVStore, addr basecoin.Actor, coins types.Coins, seq int) (types.Coins, error) {
|
||||
func (a Accountant) ChangeCoins(store state.KVStore, addr basecoin.Actor, coins Coins, seq int) (Coins, error) {
|
||||
acct, err := a.updateCoins(store, addr, coins, seq)
|
||||
if err != nil {
|
||||
return acct.Coins, err
|
||||
@@ -58,7 +57,7 @@ func (a Accountant) ChangeCoins(store state.KVStore, addr basecoin.Actor, coins
|
||||
// updateCoins will load the account, make all checks, and return the updated account.
|
||||
//
|
||||
// it doesn't save anything, that is up to you to decide (Check/Change Coins)
|
||||
func (a Accountant) updateCoins(store state.KVStore, addr basecoin.Actor, coins types.Coins, seq int) (acct Account, err error) {
|
||||
func (a Accountant) updateCoins(store state.KVStore, addr basecoin.Actor, coins Coins, seq int) (acct Account, err error) {
|
||||
acct, err = loadAccount(store, a.MakeKey(addr))
|
||||
// we can increase an empty account...
|
||||
if IsNoAccountErr(err) && coins.IsPositive() {
|
||||
@@ -98,8 +97,8 @@ func (a Accountant) MakeKey(addr basecoin.Actor) []byte {
|
||||
|
||||
// Account - coin account structure
|
||||
type Account struct {
|
||||
Coins types.Coins `json:"coins"`
|
||||
Sequence int `json:"sequence"`
|
||||
Coins Coins `json:"coins"`
|
||||
Sequence int `json:"sequence"`
|
||||
}
|
||||
|
||||
func loadAccount(store state.KVStore, key []byte) (acct Account, err error) {
|
||||
|
||||
+5
-6
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -22,7 +21,7 @@ const (
|
||||
// TxInput - expected coin movement outputs, used with SendTx
|
||||
type TxInput struct {
|
||||
Address basecoin.Actor `json:"address"`
|
||||
Coins types.Coins `json:"coins"`
|
||||
Coins Coins `json:"coins"`
|
||||
Sequence int `json:"sequence"` // Nonce: Must be 1 greater than the last committed TxInput
|
||||
}
|
||||
|
||||
@@ -52,7 +51,7 @@ func (txIn TxInput) String() string {
|
||||
}
|
||||
|
||||
// NewTxInput - create a transaction input, used with SendTx
|
||||
func NewTxInput(addr basecoin.Actor, coins types.Coins, sequence int) TxInput {
|
||||
func NewTxInput(addr basecoin.Actor, coins Coins, sequence int) TxInput {
|
||||
input := TxInput{
|
||||
Address: addr,
|
||||
Coins: coins,
|
||||
@@ -66,7 +65,7 @@ func NewTxInput(addr basecoin.Actor, coins types.Coins, sequence int) TxInput {
|
||||
// TxOutput - expected coin movement output, used with SendTx
|
||||
type TxOutput struct {
|
||||
Address basecoin.Actor `json:"address"`
|
||||
Coins types.Coins `json:"coins"`
|
||||
Coins Coins `json:"coins"`
|
||||
}
|
||||
|
||||
// ValidateBasic - validate transaction output
|
||||
@@ -92,7 +91,7 @@ func (txOut TxOutput) String() string {
|
||||
}
|
||||
|
||||
// NewTxOutput - create a transaction output, used with SendTx
|
||||
func NewTxOutput(addr basecoin.Actor, coins types.Coins) TxOutput {
|
||||
func NewTxOutput(addr basecoin.Actor, coins Coins) TxOutput {
|
||||
output := TxOutput{
|
||||
Address: addr,
|
||||
Coins: coins,
|
||||
@@ -127,7 +126,7 @@ func (tx SendTx) ValidateBasic() error {
|
||||
return ErrNoOutputs()
|
||||
}
|
||||
// make sure all inputs and outputs are individually valid
|
||||
var totalIn, totalOut types.Coins
|
||||
var totalIn, totalOut Coins
|
||||
for _, in := range tx.Inputs {
|
||||
if err := in.ValidateBasic(); err != nil {
|
||||
return err
|
||||
|
||||
+20
-19
@@ -5,9 +5,10 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
|
||||
"github.com/tendermint/go-wire/data"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
)
|
||||
|
||||
// these are some constructs for the test cases
|
||||
@@ -24,22 +25,22 @@ var actors = []struct {
|
||||
}
|
||||
|
||||
var (
|
||||
zeroCoin = types.Coin{"zeros", 0}
|
||||
plusCoin = types.Coin{"plus", 23}
|
||||
negCoin = types.Coin{"neg", -42}
|
||||
zeroCoin = Coin{"zeros", 0}
|
||||
plusCoin = Coin{"plus", 23}
|
||||
negCoin = Coin{"neg", -42}
|
||||
)
|
||||
|
||||
var coins = []struct {
|
||||
coins types.Coins
|
||||
coins Coins
|
||||
valid bool
|
||||
}{
|
||||
{types.Coins{}, false},
|
||||
{types.Coins{zeroCoin}, false},
|
||||
{types.Coins{plusCoin}, true},
|
||||
{types.Coins{negCoin}, false},
|
||||
{types.Coins{plusCoin, plusCoin}, false},
|
||||
{types.Coins{plusCoin, zeroCoin}, false},
|
||||
{types.Coins{negCoin, plusCoin}, false},
|
||||
{Coins{}, false},
|
||||
{Coins{zeroCoin}, false},
|
||||
{Coins{plusCoin}, true},
|
||||
{Coins{negCoin}, false},
|
||||
{Coins{plusCoin, plusCoin}, false},
|
||||
{Coins{plusCoin, zeroCoin}, false},
|
||||
{Coins{negCoin, plusCoin}, false},
|
||||
}
|
||||
|
||||
func TestTxValidateInput(t *testing.T) {
|
||||
@@ -94,12 +95,12 @@ func TestTxValidateTx(t *testing.T) {
|
||||
addr3 := basecoin.Actor{App: "role", Address: []byte{7, 8}}
|
||||
noAddr := basecoin.Actor{}
|
||||
|
||||
noCoins := types.Coins{}
|
||||
someCoins := types.Coins{{"atom", 123}}
|
||||
moreCoins := types.Coins{{"atom", 124}}
|
||||
otherCoins := types.Coins{{"btc", 15}}
|
||||
noCoins := Coins{}
|
||||
someCoins := Coins{{"atom", 123}}
|
||||
moreCoins := Coins{{"atom", 124}}
|
||||
otherCoins := Coins{{"btc", 15}}
|
||||
bothCoins := someCoins.Plus(otherCoins)
|
||||
minusCoins := types.Coins{{"eth", -34}}
|
||||
minusCoins := Coins{{"eth", -34}}
|
||||
|
||||
// cases: all valid (one), all valid (multi)
|
||||
// no input, no outputs, invalid inputs, invalid outputs
|
||||
@@ -181,7 +182,7 @@ func TestTxSerializeTx(t *testing.T) {
|
||||
|
||||
addr1 := basecoin.Actor{App: "coin", Address: []byte{1, 2}}
|
||||
addr2 := basecoin.Actor{App: "coin", Address: []byte{3, 4}}
|
||||
someCoins := types.Coins{{"atom", 123}}
|
||||
someCoins := Coins{{"atom", 123}}
|
||||
|
||||
send := NewSendTx(
|
||||
[]TxInput{NewTxInput(addr1, someCoins, 2)},
|
||||
|
||||
@@ -3,9 +3,9 @@ package fee
|
||||
import (
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
"github.com/tendermint/basecoin/modules/coin"
|
||||
"github.com/tendermint/basecoin/stack"
|
||||
"github.com/tendermint/basecoin/state"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
|
||||
// NameFee - namespace for the fee module
|
||||
@@ -14,17 +14,17 @@ const NameFee = "fee"
|
||||
// AccountChecker - interface used by SimpleFeeHandler
|
||||
type AccountChecker interface {
|
||||
// Get amount checks the current amount
|
||||
GetAmount(store state.KVStore, addr basecoin.Actor) (types.Coins, error)
|
||||
GetAmount(store state.KVStore, addr basecoin.Actor) (coin.Coins, error)
|
||||
|
||||
// ChangeAmount modifies the balance by the given amount and returns the new balance
|
||||
// always returns an error if leading to negative balance
|
||||
ChangeAmount(store state.KVStore, addr basecoin.Actor, coins types.Coins) (types.Coins, error)
|
||||
ChangeAmount(store state.KVStore, addr basecoin.Actor, coins coin.Coins) (coin.Coins, error)
|
||||
}
|
||||
|
||||
// SimpleFeeHandler - checker object for fee checking
|
||||
type SimpleFeeHandler struct {
|
||||
AccountChecker
|
||||
MinFee types.Coins
|
||||
MinFee coin.Coins
|
||||
stack.PassOption
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ func (h SimpleFeeHandler) CheckTx(ctx basecoin.Context, store state.KVStore, tx
|
||||
return res, errors.ErrInvalidFormat(tx)
|
||||
}
|
||||
|
||||
fees := types.Coins{feeTx.Fee}
|
||||
fees := coin.Coins{feeTx.Fee}
|
||||
if !fees.IsGTE(h.MinFee) {
|
||||
return res, ErrInsufficientFees()
|
||||
}
|
||||
@@ -68,7 +68,7 @@ func (h SimpleFeeHandler) DeliverTx(ctx basecoin.Context, store state.KVStore, t
|
||||
return res, errors.ErrInvalidFormat(tx)
|
||||
}
|
||||
|
||||
fees := types.Coins{feeTx.Fee}
|
||||
fees := coin.Coins{feeTx.Fee}
|
||||
if !fees.IsGTE(h.MinFee) {
|
||||
return res, ErrInsufficientFees()
|
||||
}
|
||||
|
||||
+5
-4
@@ -2,9 +2,10 @@ package fee
|
||||
|
||||
import (
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
"github.com/tendermint/basecoin/modules/coin"
|
||||
)
|
||||
|
||||
// nolint
|
||||
const (
|
||||
ByteFees = 0x20
|
||||
TypeFees = "fee"
|
||||
@@ -20,12 +21,12 @@ func init() {
|
||||
// Fee attaches a fee payment to the embedded tx
|
||||
type Fee struct {
|
||||
Tx basecoin.Tx `json:"tx"`
|
||||
Fee types.Coin `json:"fee"`
|
||||
Fee coin.Coin `json:"fee"`
|
||||
Payer basecoin.Actor `json:"payer"` // the address who pays the fee
|
||||
// Gas types.Coin `json:"gas"` // ?????
|
||||
// Gas coin.Coin `json:"gas"` // ?????
|
||||
}
|
||||
|
||||
func NewFee(tx basecoin.Tx, fee types.Coin, payer basecoin.Actor) basecoin.Tx {
|
||||
func NewFee(tx basecoin.Tx, fee coin.Coin, payer basecoin.Actor) basecoin.Tx {
|
||||
return (&Fee{Tx: tx, Fee: fee, Payer: payer}).Wrap()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user