remove sequence number from coins

This commit is contained in:
Ethan Frey 2017-07-12 18:54:07 +02:00
parent 46345237a1
commit 5950ff34e3
11 changed files with 82 additions and 92 deletions

View File

@ -41,8 +41,8 @@ func newAppTest(t *testing.T) *appTest {
} }
// make a tx sending 5mycoin from each acctIn to acctOut // make a tx sending 5mycoin from each acctIn to acctOut
func (at *appTest) getTx(seq int, coins coin.Coins) basecoin.Tx { func (at *appTest) getTx(coins coin.Coins) basecoin.Tx {
in := []coin.TxInput{{Address: at.acctIn.Actor(), Coins: coins, Sequence: seq}} in := []coin.TxInput{{Address: at.acctIn.Actor(), Coins: coins}}
out := []coin.TxOutput{{Address: at.acctOut.Actor(), Coins: coins}} out := []coin.TxOutput{{Address: at.acctOut.Actor(), Coins: coins}}
tx := coin.NewSendTx(in, out) tx := coin.NewSendTx(in, out)
tx = base.NewChainTx(at.chainID, 0, tx) tx = base.NewChainTx(at.chainID, 0, tx)
@ -193,22 +193,22 @@ func TestTx(t *testing.T) {
//Bad Balance //Bad Balance
at.acctIn.Coins = coin.Coins{{"mycoin", 2}} at.acctIn.Coins = coin.Coins{{"mycoin", 2}}
at.initAccount(at.acctIn) at.initAccount(at.acctIn)
res, _, _ := at.exec(t, at.getTx(1, coin.Coins{{"mycoin", 5}}), true) res, _, _ := at.exec(t, at.getTx(coin.Coins{{"mycoin", 5}}), true)
assert.True(res.IsErr(), "ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res) assert.True(res.IsErr(), "ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res)
res, diffIn, diffOut := at.exec(t, at.getTx(1, coin.Coins{{"mycoin", 5}}), false) res, diffIn, diffOut := at.exec(t, at.getTx(coin.Coins{{"mycoin", 5}}), false)
assert.True(res.IsErr(), "ExecTx/Bad DeliverTx: Expected error return from ExecTx, returned: %v", res) assert.True(res.IsErr(), "ExecTx/Bad DeliverTx: Expected error return from ExecTx, returned: %v", res)
assert.True(diffIn.IsZero()) assert.True(diffIn.IsZero())
assert.True(diffOut.IsZero()) assert.True(diffOut.IsZero())
//Regular CheckTx //Regular CheckTx
at.reset() at.reset()
res, _, _ = at.exec(t, at.getTx(1, coin.Coins{{"mycoin", 5}}), true) res, _, _ = at.exec(t, at.getTx(coin.Coins{{"mycoin", 5}}), true)
assert.True(res.IsOK(), "ExecTx/Good CheckTx: Expected OK return from ExecTx, Error: %v", res) assert.True(res.IsOK(), "ExecTx/Good CheckTx: Expected OK return from ExecTx, Error: %v", res)
//Regular DeliverTx //Regular DeliverTx
at.reset() at.reset()
amt := coin.Coins{{"mycoin", 3}} amt := coin.Coins{{"mycoin", 3}}
res, diffIn, diffOut = at.exec(t, at.getTx(1, amt), false) res, diffIn, diffOut = at.exec(t, at.getTx(amt), false)
assert.True(res.IsOK(), "ExecTx/Good DeliverTx: Expected OK return from ExecTx, Error: %v", res) assert.True(res.IsOK(), "ExecTx/Good DeliverTx: Expected OK return from ExecTx, Error: %v", res)
assert.Equal(amt.Negative(), diffIn) assert.Equal(amt.Negative(), diffIn)
assert.Equal(amt, diffOut) assert.Equal(amt, diffOut)
@ -218,7 +218,7 @@ func TestQuery(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
at := newAppTest(t) at := newAppTest(t)
res, _, _ := at.exec(t, at.getTx(1, coin.Coins{{"mycoin", 5}}), false) res, _, _ := at.exec(t, at.getTx(coin.Coins{{"mycoin", 5}}), false)
assert.True(res.IsOK(), "Commit, DeliverTx: Expected OK return from DeliverTx, Error: %v", res) assert.True(res.IsOK(), "Commit, DeliverTx: Expected OK return from DeliverTx, Error: %v", res)
resQueryPreCommit := at.app.Query(abci.RequestQuery{ resQueryPreCommit := at.app.Query(abci.RequestQuery{

View File

@ -125,9 +125,8 @@ func readSendTxFlags() (tx basecoin.Tx, err error) {
// craft the inputs and outputs // craft the inputs and outputs
ins := []coin.TxInput{{ ins := []coin.TxInput{{
Address: fromAddr, Address: fromAddr,
Coins: amountCoins, Coins: amountCoins,
Sequence: viper.GetInt(FlagSequence),
}} }}
outs := []coin.TxOutput{{ outs := []coin.TxOutput{{
Address: toAddr, Address: toAddr,

View File

@ -145,7 +145,7 @@ func (h Handler) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoi
if len(senders) == 0 { if len(senders) == 0 {
return res, errors.ErrMissingSignature() return res, errors.ErrMissingSignature()
} }
in := []coin.TxInput{{Address: senders[0], Coins: ctr.Fee, Sequence: ctr.Sequence}} in := []coin.TxInput{{Address: senders[0], Coins: ctr.Fee}}
out := []coin.TxOutput{{Address: StoreActor(), Coins: ctr.Fee}} out := []coin.TxOutput{{Address: StoreActor(), Coins: ctr.Fee}}
send := coin.NewSendTx(in, out) send := coin.NewSendTx(in, out)
// if the deduction fails (too high), abort the command // if the deduction fails (too high), abort the command
@ -170,7 +170,7 @@ func (h Handler) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoi
func checkTx(ctx basecoin.Context, tx basecoin.Tx) (ctr Tx, err error) { func checkTx(ctx basecoin.Context, tx basecoin.Tx) (ctr Tx, err error) {
ctr, ok := tx.Unwrap().(Tx) ctr, ok := tx.Unwrap().(Tx)
if !ok { if !ok {
return ctr, errors.ErrInvalidFormat(tx) return ctr, errors.ErrInvalidFormat(TypeTx, tx)
} }
err = ctr.ValidateBasic() err = ctr.ValidateBasic()
if err != nil { if err != nil {

View File

@ -47,8 +47,8 @@ func IsUnknownTxTypeErr(err error) bool {
return IsSameError(errUnknownTxType, err) return IsSameError(errUnknownTxType, err)
} }
func ErrInvalidFormat(tx interface{}) TMError { func ErrInvalidFormat(expected string, tx interface{}) TMError {
msg := fmt.Sprintf("%T", unwrap(tx)) msg := fmt.Sprintf("%T not %s", unwrap(tx), expected)
w := errors.Wrap(errInvalidFormat, msg) w := errors.Wrap(errInvalidFormat, msg)
return WithCode(w, abci.CodeType_UnknownRequest) return WithCode(w, abci.CodeType_UnknownRequest)
} }

View File

@ -15,8 +15,8 @@ func makeHandler() basecoin.Handler {
return NewHandler() return NewHandler()
} }
func makeSimpleTx(from, to basecoin.Actor, amount Coins, seq int) basecoin.Tx { func makeSimpleTx(from, to basecoin.Actor, amount Coins) basecoin.Tx {
in := []TxInput{{Address: from, Coins: amount, Sequence: seq}} in := []TxInput{{Address: from, Coins: amount}}
out := []TxOutput{{Address: to, Coins: amount}} out := []TxOutput{{Address: to, Coins: amount}}
return NewSendTx(in, out) return NewSendTx(in, out)
} }
@ -35,7 +35,7 @@ func BenchmarkSimpleTransfer(b *testing.B) {
// now, loop... // now, loop...
for i := 1; i <= b.N; i++ { for i := 1; i <= b.N; i++ {
ctx := stack.MockContext("foo", 100).WithPermissions(sender) ctx := stack.MockContext("foo", 100).WithPermissions(sender)
tx := makeSimpleTx(sender, receiver, Coins{{"mycoin", 2}}, i) tx := makeSimpleTx(sender, receiver, Coins{{"mycoin", 2}})
_, err := h.DeliverTx(ctx, store, tx) _, err := h.DeliverTx(ctx, store, tx)
// never should error // never should error
if err != nil { if err != nil {

View File

@ -16,10 +16,23 @@ type Coin struct {
Amount int64 `json:"amount"` Amount int64 `json:"amount"`
} }
// String provides a human-readable representation of a coin
func (coin Coin) String() string { func (coin Coin) String() string {
return fmt.Sprintf("%v%v", coin.Amount, coin.Denom) return fmt.Sprintf("%v%v", coin.Amount, coin.Denom)
} }
// IsZero returns if this represents no money
func (coin Coin) IsZero() bool {
return coin.Amount == 0
}
// IsGTE returns true if they are the same type and the receiver is
// an equal or greater value
func (coin Coin) IsGTE(other Coin) bool {
return (coin.Denom == other.Denom) &&
(coin.Amount >= other.Amount)
}
//regex codes for extracting coins from string //regex codes for extracting coins from string
var reDenom = regexp.MustCompile("") var reDenom = regexp.MustCompile("")
var reAmt = regexp.MustCompile("(\\d+)") var reAmt = regexp.MustCompile("(\\d+)")

View File

@ -37,7 +37,7 @@ func (h Handler) CheckTx(ctx basecoin.Context, store state.KVStore, tx basecoin.
// now make sure there is money // now make sure there is money
for _, in := range send.Inputs { for _, in := range send.Inputs {
_, err = CheckCoins(store, in.Address, in.Coins.Negative(), in.Sequence) _, err = CheckCoins(store, in.Address, in.Coins.Negative())
if err != nil { if err != nil {
return res, err return res, err
} }
@ -56,7 +56,7 @@ func (h Handler) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoi
// deduct from all input accounts // deduct from all input accounts
for _, in := range send.Inputs { for _, in := range send.Inputs {
_, err = ChangeCoins(store, in.Address, in.Coins.Negative(), in.Sequence) _, err = ChangeCoins(store, in.Address, in.Coins.Negative())
if err != nil { if err != nil {
return res, err return res, err
} }
@ -64,8 +64,7 @@ func (h Handler) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoi
// add to all output accounts // add to all output accounts
for _, out := range send.Outputs { for _, out := range send.Outputs {
// note: sequence number is ignored when adding coins, only checked for subtracting _, err = ChangeCoins(store, out.Address, out.Coins)
_, err = ChangeCoins(store, out.Address, out.Coins, 0)
if err != nil { if err != nil {
return res, err return res, err
} }
@ -107,7 +106,7 @@ func checkTx(ctx basecoin.Context, tx basecoin.Tx) (send SendTx, err error) {
// check if the tx is proper type and valid // check if the tx is proper type and valid
send, ok := tx.Unwrap().(SendTx) send, ok := tx.Unwrap().(SendTx)
if !ok { if !ok {
return send, errors.ErrInvalidFormat(tx) return send, errors.ErrInvalidFormat(TypeSend, tx)
} }
err = send.ValidateBasic() err = send.ValidateBasic()
if err != nil { if err != nil {

View File

@ -35,40 +35,40 @@ func TestHandlerValidation(t *testing.T) {
// auth works with different apps // auth works with different apps
{true, {true,
NewSendTx( NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, 2)}, []TxInput{NewTxInput(addr1, someCoins)},
[]TxOutput{NewTxOutput(addr2, someCoins)}), []TxOutput{NewTxOutput(addr2, someCoins)}),
[]basecoin.Actor{addr1}}, []basecoin.Actor{addr1}},
{true, {true,
NewSendTx( NewSendTx(
[]TxInput{NewTxInput(addr2, someCoins, 2)}, []TxInput{NewTxInput(addr2, someCoins)},
[]TxOutput{NewTxOutput(addr1, someCoins)}), []TxOutput{NewTxOutput(addr1, someCoins)}),
[]basecoin.Actor{addr1, addr2}}, []basecoin.Actor{addr1, addr2}},
// check multi-input with both sigs // check multi-input with both sigs
{true, {true,
NewSendTx( NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, 2), NewTxInput(addr2, someCoins, 3)}, []TxInput{NewTxInput(addr1, someCoins), NewTxInput(addr2, someCoins)},
[]TxOutput{NewTxOutput(addr1, doubleCoins)}), []TxOutput{NewTxOutput(addr1, doubleCoins)}),
[]basecoin.Actor{addr1, addr2}}, []basecoin.Actor{addr1, addr2}},
// wrong permissions fail // wrong permissions fail
{false, {false,
NewSendTx( NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, 2)}, []TxInput{NewTxInput(addr1, someCoins)},
[]TxOutput{NewTxOutput(addr2, someCoins)}), []TxOutput{NewTxOutput(addr2, someCoins)}),
[]basecoin.Actor{}}, []basecoin.Actor{}},
{false, {false,
NewSendTx( NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, 2)}, []TxInput{NewTxInput(addr1, someCoins)},
[]TxOutput{NewTxOutput(addr2, someCoins)}), []TxOutput{NewTxOutput(addr2, someCoins)}),
[]basecoin.Actor{addr2}}, []basecoin.Actor{addr2}},
{false, {false,
NewSendTx( NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, 2), NewTxInput(addr2, someCoins, 3)}, []TxInput{NewTxInput(addr1, someCoins), NewTxInput(addr2, someCoins)},
[]TxOutput{NewTxOutput(addr1, doubleCoins)}), []TxOutput{NewTxOutput(addr1, doubleCoins)}),
[]basecoin.Actor{addr1}}, []basecoin.Actor{addr1}},
// invalid input fails // invalid input fails
{false, {false,
NewSendTx( NewSendTx(
[]TxInput{NewTxInput(addr1, minusCoins, 2)}, []TxInput{NewTxInput(addr1, minusCoins)},
[]TxOutput{NewTxOutput(addr2, minusCoins)}), []TxOutput{NewTxOutput(addr2, minusCoins)}),
[]basecoin.Actor{addr2}}, []basecoin.Actor{addr2}},
} }
@ -113,7 +113,7 @@ func TestDeliverTx(t *testing.T) {
{ {
[]money{{addr1, moreCoins}}, []money{{addr1, moreCoins}},
NewSendTx( NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, 1)}, []TxInput{NewTxInput(addr1, someCoins)},
[]TxOutput{NewTxOutput(addr2, someCoins)}), []TxOutput{NewTxOutput(addr2, someCoins)}),
[]basecoin.Actor{addr1}, []basecoin.Actor{addr1},
[]money{{addr1, diffCoins}, {addr2, someCoins}}, []money{{addr1, diffCoins}, {addr2, someCoins}},
@ -122,7 +122,7 @@ func TestDeliverTx(t *testing.T) {
{ {
[]money{{addr1, mixedCoins}, {addr2, moreCoins}}, []money{{addr1, mixedCoins}, {addr2, moreCoins}},
NewSendTx( NewSendTx(
[]TxInput{NewTxInput(addr1, otherCoins, 1), NewTxInput(addr2, someCoins, 1)}, []TxInput{NewTxInput(addr1, otherCoins), NewTxInput(addr2, someCoins)},
[]TxOutput{NewTxOutput(addr3, mixedCoins)}), []TxOutput{NewTxOutput(addr3, mixedCoins)}),
[]basecoin.Actor{addr1, addr2}, []basecoin.Actor{addr1, addr2},
[]money{{addr1, someCoins}, {addr2, diffCoins}, {addr3, mixedCoins}}, []money{{addr1, someCoins}, {addr2, diffCoins}, {addr3, mixedCoins}},
@ -131,7 +131,7 @@ func TestDeliverTx(t *testing.T) {
{ {
[]money{{addr1, moreCoins.Plus(otherCoins)}}, []money{{addr1, moreCoins.Plus(otherCoins)}},
NewSendTx( NewSendTx(
[]TxInput{NewTxInput(addr1, otherCoins, 1), NewTxInput(addr1, someCoins, 2)}, []TxInput{NewTxInput(addr1, otherCoins), NewTxInput(addr1, someCoins)},
[]TxOutput{NewTxOutput(addr2, mixedCoins)}), []TxOutput{NewTxOutput(addr2, mixedCoins)}),
[]basecoin.Actor{addr1}, []basecoin.Actor{addr1},
[]money{{addr1, diffCoins}, {addr2, mixedCoins}}, []money{{addr1, diffCoins}, {addr2, mixedCoins}},

View File

@ -22,14 +22,14 @@ func GetAccount(store state.KVStore, addr basecoin.Actor) (Account, error) {
} }
// CheckCoins makes sure there are funds, but doesn't change anything // CheckCoins makes sure there are funds, but doesn't change anything
func CheckCoins(store state.KVStore, addr basecoin.Actor, coins Coins, seq int) (Coins, error) { func CheckCoins(store state.KVStore, addr basecoin.Actor, coins Coins) (Coins, error) {
acct, err := updateCoins(store, addr, coins, seq) acct, err := updateCoins(store, addr, coins)
return acct.Coins, err return acct.Coins, err
} }
// ChangeCoins changes the money, returns error if it would be negative // ChangeCoins changes the money, returns error if it would be negative
func ChangeCoins(store state.KVStore, addr basecoin.Actor, coins Coins, seq int) (Coins, error) { func ChangeCoins(store state.KVStore, addr basecoin.Actor, coins Coins) (Coins, error) {
acct, err := updateCoins(store, addr, coins, seq) acct, err := updateCoins(store, addr, coins)
if err != nil { if err != nil {
return acct.Coins, err return acct.Coins, err
} }
@ -41,7 +41,7 @@ func ChangeCoins(store state.KVStore, addr basecoin.Actor, coins Coins, seq int)
// updateCoins will load the account, make all checks, and return the updated account. // 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) // it doesn't save anything, that is up to you to decide (Check/Change Coins)
func updateCoins(store state.KVStore, addr basecoin.Actor, coins Coins, seq int) (acct Account, err error) { func updateCoins(store state.KVStore, addr basecoin.Actor, coins Coins) (acct Account, err error) {
acct, err = loadAccount(store, addr.Bytes()) acct, err = loadAccount(store, addr.Bytes())
// we can increase an empty account... // we can increase an empty account...
if IsNoAccountErr(err) && coins.IsPositive() { if IsNoAccountErr(err) && coins.IsPositive() {
@ -51,14 +51,6 @@ func updateCoins(store state.KVStore, addr basecoin.Actor, coins Coins, seq int)
return acct, err return acct, err
} }
// check sequence if we are deducting... ugh, need a cleaner replay protection
if !coins.IsPositive() {
if seq != acct.Sequence+1 {
return acct, ErrInvalidSequence()
}
acct.Sequence++
}
// check amount // check amount
final := acct.Coins.Plus(coins) final := acct.Coins.Plus(coins)
if !final.IsNonnegative() { if !final.IsNonnegative() {

View File

@ -20,9 +20,8 @@ const (
// TxInput - expected coin movement outputs, used with SendTx // TxInput - expected coin movement outputs, used with SendTx
type TxInput struct { type TxInput struct {
Address basecoin.Actor `json:"address"` Address basecoin.Actor `json:"address"`
Coins Coins `json:"coins"` Coins Coins `json:"coins"`
Sequence int `json:"sequence"` // Nonce: Must be 1 greater than the last committed TxInput
} }
// ValidateBasic - validate transaction input // ValidateBasic - validate transaction input
@ -40,22 +39,18 @@ func (txIn TxInput) ValidateBasic() error {
if !txIn.Coins.IsPositive() { if !txIn.Coins.IsPositive() {
return ErrInvalidCoins() return ErrInvalidCoins()
} }
if txIn.Sequence <= 0 {
return ErrInvalidSequence()
}
return nil return nil
} }
func (txIn TxInput) String() string { func (txIn TxInput) String() string {
return fmt.Sprintf("TxInput{%v,%v,%v}", txIn.Address, txIn.Coins, txIn.Sequence) return fmt.Sprintf("TxInput{%v,%v}", txIn.Address, txIn.Coins)
} }
// NewTxInput - create a transaction input, used with SendTx // NewTxInput - create a transaction input, used with SendTx
func NewTxInput(addr basecoin.Actor, coins Coins, sequence int) TxInput { func NewTxInput(addr basecoin.Actor, coins Coins) TxInput {
input := TxInput{ input := TxInput{
Address: addr, Address: addr,
Coins: coins, Coins: coins,
Sequence: sequence,
} }
return input return input
} }
@ -110,11 +105,19 @@ type SendTx struct {
var _ basecoin.Tx = NewSendTx(nil, nil) var _ basecoin.Tx = NewSendTx(nil, nil)
// NewSendTx - new SendTx // NewSendTx - construct arbitrary multi-in, multi-out sendtx
func NewSendTx(in []TxInput, out []TxOutput) basecoin.Tx { func NewSendTx(in []TxInput, out []TxOutput) basecoin.Tx {
return SendTx{Inputs: in, Outputs: out}.Wrap() return SendTx{Inputs: in, Outputs: out}.Wrap()
} }
// NewSendOneTx is a helper for the standard (?) case where there is exactly
// one sender and one recipient
func NewSendOneTx(sender, recipient basecoin.Actor, amount Coins) basecoin.Tx {
in := []TxInput{{Address: sender, Coins: amount}}
out := []TxOutput{{Address: recipient, Coins: amount}}
return SendTx{Inputs: in, Outputs: out}.Wrap()
}
// ValidateBasic - validate the send transaction // ValidateBasic - validate the send transaction
func (tx SendTx) ValidateBasic() error { func (tx SendTx) ValidateBasic() error {
// this just makes sure all the inputs and outputs are properly formatted, // this just makes sure all the inputs and outputs are properly formatted,

View File

@ -46,26 +46,14 @@ var coins = []struct {
func TestTxValidateInput(t *testing.T) { func TestTxValidateInput(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
seqs := []struct {
seq int
valid bool
}{
{-3, false},
{0, false},
{1, true},
{6571265735, true},
}
for i, act := range actors { for i, act := range actors {
for j, coin := range coins { for j, coin := range coins {
for k, seq := range seqs { input := NewTxInput(act.actor, coin.coins)
input := NewTxInput(act.actor, coin.coins, seq.seq) err := input.ValidateBasic()
err := input.ValidateBasic() if act.valid && coin.valid {
if act.valid && coin.valid && seq.valid { assert.Nil(err, "%d,%d: %+v", i, j, err)
assert.Nil(err, "%d,%d,%d: %+v", i, j, k, err) } else {
} else { assert.NotNil(err, "%d,%d", i, j)
assert.NotNil(err, "%d,%d,%d", i, j, k)
}
} }
} }
} }
@ -111,15 +99,15 @@ func TestTxValidateTx(t *testing.T) {
}{ }{
// 0-2. valid cases // 0-2. valid cases
{true, NewSendTx( {true, NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, 2)}, []TxInput{NewTxInput(addr1, someCoins)},
[]TxOutput{NewTxOutput(addr2, someCoins)}, []TxOutput{NewTxOutput(addr2, someCoins)},
)}, )},
{true, NewSendTx( {true, NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, 2), NewTxInput(addr2, otherCoins, 5)}, []TxInput{NewTxInput(addr1, someCoins), NewTxInput(addr2, otherCoins)},
[]TxOutput{NewTxOutput(addr3, bothCoins)}, []TxOutput{NewTxOutput(addr3, bothCoins)},
)}, )},
{true, NewSendTx( {true, NewSendTx(
[]TxInput{NewTxInput(addr1, bothCoins, 42)}, []TxInput{NewTxInput(addr1, bothCoins)},
[]TxOutput{NewTxOutput(addr2, someCoins), NewTxOutput(addr3, otherCoins)}, []TxOutput{NewTxOutput(addr2, someCoins), NewTxOutput(addr3, otherCoins)},
)}, )},
@ -129,39 +117,35 @@ func TestTxValidateTx(t *testing.T) {
[]TxOutput{NewTxOutput(addr2, someCoins)}, []TxOutput{NewTxOutput(addr2, someCoins)},
)}, )},
{false, NewSendTx( {false, NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, 2)}, []TxInput{NewTxInput(addr1, someCoins)},
nil, nil,
)}, )},
// 5-8. invalid inputs // 5-7. invalid inputs
{false, NewSendTx( {false, NewSendTx(
[]TxInput{NewTxInput(noAddr, someCoins, 2)}, []TxInput{NewTxInput(noAddr, someCoins)},
[]TxOutput{NewTxOutput(addr2, someCoins)}, []TxOutput{NewTxOutput(addr2, someCoins)},
)}, )},
{false, NewSendTx( {false, NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, -1)}, []TxInput{NewTxInput(addr1, noCoins)},
[]TxOutput{NewTxOutput(addr2, someCoins)},
)},
{false, NewSendTx(
[]TxInput{NewTxInput(addr1, noCoins, 2)},
[]TxOutput{NewTxOutput(addr2, noCoins)}, []TxOutput{NewTxOutput(addr2, noCoins)},
)}, )},
{false, NewSendTx( {false, NewSendTx(
[]TxInput{NewTxInput(addr1, minusCoins, 2)}, []TxInput{NewTxInput(addr1, minusCoins)},
[]TxOutput{NewTxOutput(addr2, minusCoins)}, []TxOutput{NewTxOutput(addr2, minusCoins)},
)}, )},
// 9-11. totals don't match // 8-10. totals don't match
{false, NewSendTx( {false, NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, 7)}, []TxInput{NewTxInput(addr1, someCoins)},
[]TxOutput{NewTxOutput(addr2, moreCoins)}, []TxOutput{NewTxOutput(addr2, moreCoins)},
)}, )},
{false, NewSendTx( {false, NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, 2), NewTxInput(addr2, minusCoins, 5)}, []TxInput{NewTxInput(addr1, someCoins), NewTxInput(addr2, minusCoins)},
[]TxOutput{NewTxOutput(addr3, someCoins)}, []TxOutput{NewTxOutput(addr3, someCoins)},
)}, )},
{false, NewSendTx( {false, NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, 2), NewTxInput(addr2, moreCoins, 5)}, []TxInput{NewTxInput(addr1, someCoins), NewTxInput(addr2, moreCoins)},
[]TxOutput{NewTxOutput(addr3, bothCoins)}, []TxOutput{NewTxOutput(addr3, bothCoins)},
)}, )},
} }
@ -185,7 +169,7 @@ func TestTxSerializeTx(t *testing.T) {
someCoins := Coins{{"atom", 123}} someCoins := Coins{{"atom", 123}}
send := NewSendTx( send := NewSendTx(
[]TxInput{NewTxInput(addr1, someCoins, 2)}, []TxInput{NewTxInput(addr1, someCoins)},
[]TxOutput{NewTxOutput(addr2, someCoins)}, []TxOutput{NewTxOutput(addr2, someCoins)},
) )