From 16ff0ccf4f801aad2bf0ef243048e835ded6cedd Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 21 Mar 2017 17:16:40 -0400 Subject: [PATCH] finished execution test int interim, tests finalized --- app/app.go | 2 +- app/app_test.go | 226 ++++++++++++++++++++++++++++++++++++++++ state/execution.go | 6 -- state/execution_test.go | 64 +++++++----- 4 files changed, 267 insertions(+), 31 deletions(-) create mode 100644 app/app_test.go diff --git a/app/app.go b/app/app.go index c20e220b7..f8cc5b739 100644 --- a/app/app.go +++ b/app/app.go @@ -136,7 +136,7 @@ func (app *Basecoin) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQu // handle special path for account info if reqQuery.Path == "/account" { reqQuery.Path = "/key" - reqQuery.Data = append([]byte("base/a/"), reqQuery.Data...) + reqQuery.Data = sm.AccountKey(reqQuery.Data) } resQuery, err := app.eyesCli.QuerySync(reqQuery) diff --git a/app/app_test.go b/app/app_test.go new file mode 100644 index 000000000..7bb63b21e --- /dev/null +++ b/app/app_test.go @@ -0,0 +1,226 @@ +package app + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + abci "github.com/tendermint/abci/types" + "github.com/tendermint/basecoin/types" + "github.com/tendermint/go-crypto" + "github.com/tendermint/go-wire" + eyes "github.com/tendermint/merkleeyes/client" +) + +//TODO: + +//Query - +//Commit - see if commit works before and after + +///////////////////// +// Testing functions + +func makeAccs(secrets []string) (accs []types.PrivAccount) { + for _, secret := range secrets { + privAcc := types.PrivAccountFromSecret(secret) + privAcc.Account.Balance = types.Coins{{"mycoin", 7}} + accs = append(accs, privAcc) + } + return +} + +const chainID = "testChain" + +func TestSplitKey(t *testing.T) { + assert := assert.New(t) + prefix, suffix := splitKey("foo/bar") + assert.EqualValues("foo", prefix) + assert.EqualValues("bar", suffix) + + prefix, suffix = splitKey("foobar") + assert.EqualValues("foobar", prefix) + assert.EqualValues("", suffix) +} + +func TestSetOption(t *testing.T) { + assert := assert.New(t) + + eyesCli := eyes.NewLocalClient("", 0) + app := NewBasecoin(eyesCli) + + //testing ChainID + res := app.SetOption("base/chain_id", chainID) + assert.EqualValues(app.GetState().GetChainID(), chainID) + assert.EqualValues(res, "Success") + + accsFoo := makeAccs([]string{"foo"}) + accsFooBytes, err := json.Marshal(accsFoo[0].Account) + assert.Nil(err) + res = app.SetOption("base/account", string(accsFooBytes)) + assert.EqualValues(res, "Success") + + res = app.SetOption("base/dslfkgjdas", "") + assert.NotEqual(res, "Success") + + res = app.SetOption("dslfkgjdas", "") + assert.NotEqual(res, "Success") + + res = app.SetOption("dslfkgjdas/szfdjzs", "") + assert.NotEqual(res, "Success") +} + +//CheckTx - bad bytes, bad tx, good tx. +//DeliverTx - bad bytes, bad tx, good tx. +func TestTx(t *testing.T) { + assert := assert.New(t) + + var accsFoo, accsBar []types.PrivAccount + + var app *Basecoin + + acc2app := func(acc types.Account) { + accBytes, err := json.Marshal(acc) + assert.Nil(err) + res := app.SetOption("base/account", string(accBytes)) + assert.EqualValues(res, "Success") + } + + reset := func() { + accsFoo = makeAccs([]string{"foo"}) + accsBar = makeAccs([]string{"bar"}) + + eyesCli := eyes.NewLocalClient("", 0) + app = NewBasecoin(eyesCli) + + res := app.SetOption("base/chain_id", chainID) + assert.EqualValues(res, "Success") + + acc2app(accsFoo[0].Account) + acc2app(accsBar[0].Account) + + resabci := app.Commit() + assert.True(resabci.IsOK(), resabci) + } + reset() + + accs2TxInputs := func(accs []types.PrivAccount, seq int) []types.TxInput { + var txs []types.TxInput + for _, acc := range accs { + tx := types.NewTxInput( + acc.Account.PubKey, + types.Coins{{"mycoin", 5}}, + seq) + txs = append(txs, tx) + } + return txs + } + + //turn a list of accounts into basic list of transaction outputs + accs2TxOutputs := func(accs []types.PrivAccount) []types.TxOutput { + var txs []types.TxOutput + for _, acc := range accs { + tx := types.TxOutput{ + acc.Account.PubKey.Address(), + types.Coins{{"mycoin", 4}}} + txs = append(txs, tx) + } + return txs + } + + getTx := func(seq int) *types.SendTx { + txs := &types.SendTx{ + Gas: 0, + Fee: types.Coin{"mycoin", 1}, + Inputs: accs2TxInputs(accsFoo, seq), + Outputs: accs2TxOutputs(accsBar), + } + signBytes := txs.SignBytes(chainID) + for i, _ := range txs.Inputs { + txs.Inputs[i].Signature = crypto.SignatureS{accsFoo[i].Sign(signBytes)} + } + + return txs + } + txs := getTx(1) + + exec := func(checkTx bool) (res abci.Result, foo, fooExp, bar, barExp types.Coins) { + + initBalFoo := app.GetState().GetAccount(accsFoo[0].Account.PubKey.Address()).Balance + initBalBar := app.GetState().GetAccount(accsBar[0].Account.PubKey.Address()).Balance + + txBytes := []byte(wire.BinaryBytes(struct { + types.Tx `json:"unwrap"` + }{txs})) + + if checkTx { + res = app.CheckTx(txBytes) + } else { + res = app.DeliverTx(txBytes) + } + + endBalFoo := app.GetState().GetAccount(accsFoo[0].Account.PubKey.Address()).Balance + endBalBar := app.GetState().GetAccount(accsBar[0].Account.PubKey.Address()).Balance + decrBalFooExp := txs.Outputs[0].Coins.Plus(types.Coins{txs.Fee}) + return res, endBalFoo, initBalFoo.Minus(decrBalFooExp), endBalBar, initBalBar.Plus(txs.Outputs[0].Coins) + } + + //Bad Balance + accsFoo[0].Balance = types.Coins{{"mycoin", 2}} + acc2app(accsFoo[0].Account) + res, _, _, _, _ := exec(true) + assert.True(res.IsErr(), fmt.Sprintf("ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res)) + res, foo, fooexp, bar, barexp := exec(false) + assert.True(res.IsErr(), fmt.Sprintf("ExecTx/Bad DeliverTx: Expected error return from ExecTx, returned: %v", res)) + assert.True(!foo.IsEqual(fooexp), fmt.Sprintf("ExecTx/Bad DeliverTx: shouldn't be equal, foo: %v, fooExp: %v", foo, fooexp)) + assert.True(!bar.IsEqual(barexp), fmt.Sprintf("ExecTx/Bad DeliverTx: shouldn't be equal, bar: %v, barExp: %v", bar, barexp)) + + //Regular CheckTx + reset() + res, _, _, _, _ = exec(true) + assert.True(res.IsOK(), fmt.Sprintf("ExecTx/Good CheckTx: Expected OK return from ExecTx, Error: %v", res)) + + //Regular DeliverTx + reset() + res, foo, fooexp, bar, barexp = exec(false) + assert.True(res.IsOK(), fmt.Sprintf("ExecTx/Good DeliverTx: Expected OK return from ExecTx, Error: %v", res)) + assert.True(foo.IsEqual(fooexp), fmt.Sprintf("ExecTx/good DeliverTx: unexpected change in input coins, foo: %v, fooExp: %v", foo, fooexp)) + assert.True(bar.IsEqual(barexp), fmt.Sprintf("ExecTx/good DeliverTx: unexpected change in output coins, bar: %v, barExp: %v", bar, barexp)) + + /////////////////////// + //test Commit/Query + //After Delivered TX foo should have no more coins to send, + // but because the state hasn't yet been committed, checkTx should still + // pass but after a commit it shouldn't + + reset() + + txs = getTx(1) + res, _, _, _, _ = exec(false) + assert.True(res.IsOK(), fmt.Sprintf("Commit, CheckTx: Expected OK return from CheckTx, Error: %v", res)) + + txs = getTx(2) + res, _, _, _, _ = exec(true) + assert.True(res.IsOK(), fmt.Sprintf("Commit, CheckTx: Expected OK return from CheckTx, Error: %v", res)) + + resQueryPreCommit := app.Query(abci.RequestQuery{ + Path: "/account", + Data: accsFoo[0].Account.PubKey.Address(), + }) + + res = app.Commit() + assert.True(res.IsOK(), res) + + resQueryPostCommit := app.Query(abci.RequestQuery{ + Path: "/account", + Data: accsFoo[0].Account.PubKey.Address(), + }) + fmt.Println(resQueryPreCommit) + fmt.Println(resQueryPostCommit) + + assert.NotEqual(resQueryPreCommit, resQueryPostCommit, "Query should change before/after commit") + txs = getTx(3) + res, _, _, _, _ = exec(true) + assert.True(res.IsErr(), fmt.Sprintf("Commit, CheckTx: Expected error return from CheckTx, returned: %v", res)) + +} diff --git a/state/execution.go b/state/execution.go index 1cd536533..eb7f3c690 100644 --- a/state/execution.go +++ b/state/execution.go @@ -1,8 +1,6 @@ package state import ( - "fmt" - abci "github.com/tendermint/abci/types" "github.com/tendermint/basecoin/types" cmn "github.com/tendermint/go-common" @@ -221,7 +219,6 @@ func validateInputsBasic(ins []types.TxInput) (res abci.Result) { // Validate inputs and compute total amount of coins func validateInputsAdvanced(accounts map[string]*types.Account, signBytes []byte, ins []types.TxInput) (total types.Coins, res abci.Result) { for _, in := range ins { - fmt.Println("IN", in) acc := accounts[string(in.Address)] if acc == nil { cmn.PanicSanity("validateInputsAdvanced() expects account in accounts") @@ -247,9 +244,6 @@ func validateInputAdvanced(acc *types.Account, signBytes []byte, in types.TxInpu return abci.ErrBaseInsufficientFunds.AppendLog(cmn.Fmt("balance is %v, tried to send %v", balance, in.Coins)) } // Check signatures - fmt.Printf("signbytes %X\n", signBytes) - fmt.Println("PUBKEY", acc.PubKey) - fmt.Println("") if !acc.PubKey.VerifyBytes(signBytes, in.Signature.Signature) { return abci.ErrBaseInvalidSignature.AppendLog(cmn.Fmt("SignBytes: %X", signBytes)) } diff --git a/state/execution_test.go b/state/execution_test.go index a0afbaa65..98d5848f2 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/assert" + abci "github.com/tendermint/abci/types" "github.com/tendermint/basecoin/types" "github.com/tendermint/go-crypto" ) @@ -48,7 +49,7 @@ func TestExecution(t *testing.T) { for _, acc := range accs { tx := types.NewTxInput( acc.Account.PubKey, - types.Coins{{"mycoin", 10}}, + types.Coins{{"mycoin", 5}}, 1) txs = append(txs, tx) } @@ -61,7 +62,7 @@ func TestExecution(t *testing.T) { for _, acc := range accs { tx := types.TxOutput{ acc.Account.PubKey.Address(), - types.Coins{{"mycoin", 9}}} + types.Coins{{"mycoin", 4}}} txs = append(txs, tx) } return txs @@ -148,9 +149,7 @@ func TestExecution(t *testing.T) { _, res1 := getOrMakeOutputs(state, nil, txs1) mapRes2, res2 := getOrMakeOutputs(state, nil, txs2) - //TODO Fix this commented out test //test the map results - //acc2, map2ok := mapRes2[string(txs2[0].Address)] _, map2ok := mapRes2[string(txs2[0].Address)] return []er{ @@ -158,7 +157,6 @@ func TestExecution(t *testing.T) { {!res2.IsErr(), "getOrMakeOutputs: error when sending to new account"}, {map2ok, "getOrMakeOutputs: account output does not contain new account map item"}, } - //{accs2[0].PubKey.Equals(acc2.PubKey), "getOrMakeOutputs: account output does not contain new account pointer"}} }}, //validate input basic @@ -294,30 +292,48 @@ func TestExecution(t *testing.T) { Outputs: accs2TxOutputs(accsBar), } - initBalFoo := accsFooBar[0].Account.Balance - initBalBar := accsFooBar[1].Account.Balance - acc2State(accsFooBar) + acc2State(accsFoo) + acc2State(accsBar) + signSend(txs, accsFoo) - //sign that puppy - signBytes := txs.SignBytes(chainID) - sig := accsFoo[0].Sign(signBytes) - txs.Inputs[0].Signature = crypto.SignatureS{sig} + exec := func(checkTx bool) (ExecTxRes abci.Result, foo, fooExp, bar, barExp types.Coins) { - //TODO tests for CheckTx, some bad transactions - err := ExecTx(state, nil, txs, false, nil) - fmt.Println("ERR", err) + initBalFoo := state.GetAccount(accsFoo[0].Account.PubKey.Address()).Balance + initBalBar := state.GetAccount(accsBar[0].Account.PubKey.Address()).Balance + res := ExecTx(state, nil, txs, checkTx, nil) + endBalFoo := state.GetAccount(accsFoo[0].Account.PubKey.Address()).Balance + endBalBar := state.GetAccount(accsBar[0].Account.PubKey.Address()).Balance + decrBalFooExp := txs.Outputs[0].Coins.Plus(types.Coins{txs.Fee}) + return res, endBalFoo, initBalFoo.Minus(decrBalFooExp), endBalBar, initBalBar.Plus(txs.Outputs[0].Coins) + } - endBalFoo := state.GetAccount(accsFooBar[0].Account.PubKey.Address()).Balance - endBalBar := state.GetAccount(accsFooBar[1].Account.PubKey.Address()).Balance - decrBalFoo := initBalFoo.Minus(endBalFoo) - decrBalFooExp := txs.Outputs[0].Coins.Plus(types.Coins{txs.Fee}) - incrBalBar := endBalBar.Minus(initBalBar) + //Bad Balance + accsFoo[0].Balance = types.Coins{{"mycoin", 2}} + acc2State(accsFoo) + res1, _, _, _, _ := exec(true) + res2, foo2, fooexp2, bar2, barexp2 := exec(false) + + //Regular CheckTx + reset() + acc2State(accsFoo) + acc2State(accsBar) + res3, _, _, _, _ := exec(true) + + //Regular DeliverTx + reset() + acc2State(accsFoo) + acc2State(accsBar) + res4, foo4, fooexp4, bar4, barexp4 := exec(false) return []er{ - {decrBalFoo.IsEqual(decrBalFooExp), - fmt.Sprintf("ExecTx(sendTx): unexpected change in input coins. exp: %v, change: %v", decrBalFooExp.String(), decrBalFoo.String())}, - {incrBalBar.IsEqual(txs.Outputs[0].Coins), - fmt.Sprintf("ExecTx(sendTx): unexpected change in output coins. exp: %v, change: %v", incrBalBar.String(), txs.Outputs[0].Coins.String())}, + {res1.IsErr(), fmt.Sprintf("ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res1)}, + {res2.IsErr(), fmt.Sprintf("ExecTx/Bad DeliverTx: Expected error return from ExecTx, returned: %v", res2)}, + {!foo2.IsEqual(fooexp2), fmt.Sprintf("ExecTx/Bad DeliverTx: shouldn't be equal, foo: %v, fooExp: %v", foo2, fooexp2)}, + {!bar2.IsEqual(barexp2), fmt.Sprintf("ExecTx/Bad DeliverTx: shouldn't be equal, bar: %v, barExp: %v", bar2, barexp2)}, + {res3.IsOK(), fmt.Sprintf("ExecTx/Good CheckTx: Expected OK return from ExecTx, Error: %v", res3)}, + {res4.IsOK(), fmt.Sprintf("ExecTx/Good DeliverTx: Expected OK return from ExecTx, Error: %v", res4)}, + {foo4.IsEqual(fooexp4), fmt.Sprintf("ExecTx/good DeliverTx: unexpected change in input coins, foo: %v, fooExp: %v", foo4, fooexp4)}, + {bar4.IsEqual(barexp4), fmt.Sprintf("ExecTx/good DeliverTx: unexpected change in output coins, bar: %v, barExp: %v", bar4, barexp4)}, } }}, }