From d19f52c8936b87382d92b01f3689bb0185cf2af4 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 28 Mar 2017 16:32:55 -0400 Subject: [PATCH] review changes int int --- app/app_test.go | 213 ++++++++++-------------- cmd/commands/tx.go | 8 +- cmd/commands/utils.go | 41 ----- cmd/commands/utils_test.go | 36 ---- state/execution_test.go | 330 ++++++++++++++++--------------------- state/state_test.go | 2 +- tests/tmsp/tmsp_test.go | 8 +- types/coin.go | 45 ++++- types/coin_test.go | 31 ++++ types/test_helpers.go | 53 ++++++ 10 files changed, 366 insertions(+), 401 deletions(-) diff --git a/app/app_test.go b/app/app_test.go index 1365a108b..1be563ed8 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -10,25 +10,10 @@ import ( 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" ) -///////////////////// -// 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") @@ -47,11 +32,12 @@ func TestSetOption(t *testing.T) { app := NewBasecoin(eyesCli) //testing ChainID + chainID := "testChain" res := app.SetOption("base/chain_id", chainID) assert.EqualValues(app.GetState().GetChainID(), chainID) assert.EqualValues(res, "Success") - accsFoo := makeAccs([]string{"foo"}) + accsFoo := types.MakeAccs("foo") accsFooBytes, err := json.Marshal(accsFoo[0].Account) assert.Nil(err) res = app.SetOption("base/account", string(accsFooBytes)) @@ -67,125 +53,30 @@ func TestSetOption(t *testing.T) { assert.NotEqual(res, "Success") } -//////////////////////// TxTest - -type testValues struct { - t *testing.T - app *Basecoin - accsFoo []types.PrivAccount - accsBar []types.PrivAccount -} - -func (tv *testValues) acc2app(acc types.Account) { - accBytes, err := json.Marshal(acc) - require.Nil(tv.t, err) - res := tv.app.SetOption("base/account", string(accBytes)) - require.EqualValues(tv.t, res, "Success") -} - -func (tv *testValues) appInit() { - tv.accsFoo = makeAccs([]string{"foo"}) - tv.accsBar = makeAccs([]string{"bar"}) - - eyesCli := eyes.NewLocalClient("", 0) - tv.app = NewBasecoin(eyesCli) - - res := tv.app.SetOption("base/chain_id", chainID) - require.EqualValues(tv.t, res, "Success") - - tv.acc2app(tv.accsFoo[0].Account) - tv.acc2app(tv.accsBar[0].Account) - - resabci := tv.app.Commit() - require.True(tv.t, resabci.IsOK(), resabci) -} - -func accs2TxInputs(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 -func accs2TxOutputs(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 -} - -func (tv testValues) getTx(seq int) *types.SendTx { - txs := &types.SendTx{ - Gas: 0, - Fee: types.Coin{"mycoin", 1}, - Inputs: accs2TxInputs(tv.accsFoo, seq), - Outputs: accs2TxOutputs(tv.accsBar), - } - signBytes := txs.SignBytes(chainID) - for i, _ := range txs.Inputs { - txs.Inputs[i].Signature = crypto.SignatureS{tv.accsFoo[i].Sign(signBytes)} - } - - return txs -} - -func (tv testValues) exec(tx *types.SendTx, checkTx bool) (res abci.Result, foo, fooExp, bar, barExp types.Coins) { - - initBalFoo := tv.app.GetState().GetAccount(tv.accsFoo[0].Account.PubKey.Address()).Balance - initBalBar := tv.app.GetState().GetAccount(tv.accsBar[0].Account.PubKey.Address()).Balance - - txBytes := []byte(wire.BinaryBytes(struct { - types.Tx `json:"unwrap"` - }{tx})) - - if checkTx { - res = tv.app.CheckTx(txBytes) - } else { - res = tv.app.DeliverTx(txBytes) - } - - endBalFoo := tv.app.GetState().GetAccount(tv.accsFoo[0].Account.PubKey.Address()).Balance - endBalBar := tv.app.GetState().GetAccount(tv.accsBar[0].Account.PubKey.Address()).Balance - decrBalFooExp := tx.Outputs[0].Coins.Plus(types.Coins{tx.Fee}) - return res, endBalFoo, initBalFoo.Minus(decrBalFooExp), endBalBar, initBalBar.Plus(tx.Outputs[0].Coins) -} - //CheckTx - bad bytes, bad tx, good tx. //DeliverTx - bad bytes, bad tx, good tx. func TestTx(t *testing.T) { assert := assert.New(t) - - tv := testValues{t: t} - tv.appInit() + at := newAppTest(t) //Bad Balance - tv.accsFoo[0].Balance = types.Coins{{"mycoin", 2}} - tv.acc2app(tv.accsFoo[0].Account) - res, _, _, _, _ := tv.exec(tv.getTx(1), true) + at.accsFoo[0].Balance = types.Coins{{"mycoin", 2}} + at.acc2app(at.accsFoo[0].Account) + res, _, _, _, _ := at.exec(at.getTx(1), true) assert.True(res.IsErr(), fmt.Sprintf("ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res)) - res, foo, fooexp, bar, barexp := tv.exec(tv.getTx(1), false) + res, foo, fooexp, bar, barexp := at.exec(at.getTx(1), 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 - tv.appInit() - res, _, _, _, _ = tv.exec(tv.getTx(1), true) + at.reset() + res, _, _, _, _ = at.exec(at.getTx(1), true) assert.True(res.IsOK(), fmt.Sprintf("ExecTx/Good CheckTx: Expected OK return from ExecTx, Error: %v", res)) //Regular DeliverTx - tv.appInit() - res, foo, fooexp, bar, barexp = tv.exec(tv.getTx(1), false) + at.reset() + res, foo, fooexp, bar, barexp = at.exec(at.getTx(1), 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)) @@ -193,25 +84,91 @@ func TestTx(t *testing.T) { func TestQuery(t *testing.T) { assert := assert.New(t) - tv := testValues{t: t} - tv.appInit() + at := newAppTest(t) - res, _, _, _, _ := tv.exec(tv.getTx(1), false) + res, _, _, _, _ := at.exec(at.getTx(1), false) assert.True(res.IsOK(), fmt.Sprintf("Commit, CheckTx: Expected OK return from CheckTx, Error: %v", res)) - resQueryPreCommit := tv.app.Query(abci.RequestQuery{ + resQueryPreCommit := at.app.Query(abci.RequestQuery{ Path: "/account", - Data: tv.accsFoo[0].Account.PubKey.Address(), + Data: at.accsFoo[0].Account.PubKey.Address(), }) - res = tv.app.Commit() + res = at.app.Commit() assert.True(res.IsOK(), res) - resQueryPostCommit := tv.app.Query(abci.RequestQuery{ + resQueryPostCommit := at.app.Query(abci.RequestQuery{ Path: "/account", - Data: tv.accsFoo[0].Account.PubKey.Address(), + Data: at.accsFoo[0].Account.PubKey.Address(), }) fmt.Println(resQueryPreCommit) fmt.Println(resQueryPostCommit) assert.NotEqual(resQueryPreCommit, resQueryPostCommit, "Query should change before/after commit") } + +///////////////////////////////////////////////////////////////// + +type appTest struct { + t *testing.T + chainID string + app *Basecoin + accsFoo []types.PrivAccount + accsBar []types.PrivAccount +} + +func newAppTest(t *testing.T) *appTest { + at := &appTest{ + t: t, + chainID: "test_chain_id", + } + at.reset() + return at +} + +func (ap *appTest) getTx(seq int) *types.SendTx { + tx := types.GetTx(seq, ap.accsFoo, ap.accsBar) + types.SignTx(ap.chainID, tx, ap.accsFoo) + return tx +} + +func (at *appTest) acc2app(acc types.Account) { + accBytes, err := json.Marshal(acc) + require.Nil(at.t, err) + res := at.app.SetOption("base/account", string(accBytes)) + require.EqualValues(at.t, res, "Success") +} + +func (at *appTest) reset() { + at.accsFoo = types.MakeAccs("foo") + at.accsBar = types.MakeAccs("bar") + + eyesCli := eyes.NewLocalClient("", 0) + at.app = NewBasecoin(eyesCli) + + res := at.app.SetOption("base/chain_id", at.chainID) + require.EqualValues(at.t, res, "Success") + + at.acc2app(at.accsFoo[0].Account) + at.acc2app(at.accsBar[0].Account) + + resabci := at.app.Commit() + require.True(at.t, resabci.IsOK(), resabci) +} + +func (at *appTest) exec(tx *types.SendTx, checkTx bool) (res abci.Result, foo, fooExp, bar, barExp types.Coins) { + + initBalFoo := at.app.GetState().GetAccount(at.accsFoo[0].Account.PubKey.Address()).Balance + initBalBar := at.app.GetState().GetAccount(at.accsBar[0].Account.PubKey.Address()).Balance + + txBytes := []byte(wire.BinaryBytes(struct{ types.Tx }{tx})) + if checkTx { + res = at.app.CheckTx(txBytes) + } else { + res = at.app.DeliverTx(txBytes) + } + + endBalFoo := at.app.GetState().GetAccount(at.accsFoo[0].Account.PubKey.Address()).Balance + endBalBar := at.app.GetState().GetAccount(at.accsBar[0].Account.PubKey.Address()).Balance + decrBalFooExp := tx.Outputs[0].Coins.Plus(types.Coins{tx.Fee}) + return res, endBalFoo, initBalFoo.Minus(decrBalFooExp), endBalBar, initBalBar.Plus(tx.Outputs[0].Coins) +} diff --git a/cmd/commands/tx.go b/cmd/commands/tx.go index b8e4bcf04..338bbcb22 100644 --- a/cmd/commands/tx.go +++ b/cmd/commands/tx.go @@ -92,11 +92,11 @@ func cmdSendTx(c *cli.Context) error { } //parse the fee and amounts into coin types - feeCoin, err := ParseCoin(fee) + feeCoin, err := types.ParseCoin(fee) if err != nil { return err } - amountCoins, err := ParseCoins(amount) + amountCoins, err := types.ParseCoins(amount) if err != nil { return err } @@ -153,11 +153,11 @@ func AppTx(c *cli.Context, name string, data []byte) error { } //parse the fee and amounts into coin types - feeCoin, err := ParseCoin(fee) + feeCoin, err := types.ParseCoin(fee) if err != nil { return err } - amountCoins, err := ParseCoins(amount) + amountCoins, err := types.ParseCoins(amount) if err != nil { return err } diff --git a/cmd/commands/utils.go b/cmd/commands/utils.go index 6348ef3cd..efff67e0b 100644 --- a/cmd/commands/utils.go +++ b/cmd/commands/utils.go @@ -4,9 +4,6 @@ import ( "encoding/hex" "errors" "os" - "regexp" - "strconv" - "strings" "github.com/urfave/cli" @@ -50,44 +47,6 @@ func StripHex(s string) string { return s } -//regex codes for extracting coins from CLI input -var reDenom = regexp.MustCompile("([^\\d\\W]+)") -var reAmt = regexp.MustCompile("(\\d+)") - -func ParseCoin(str string) (types.Coin, error) { - - var coin types.Coin - - if len(str) > 0 { - amt, err := strconv.Atoi(reAmt.FindString(str)) - if err != nil { - return coin, err - } - denom := reDenom.FindString(str) - coin = types.Coin{denom, int64(amt)} - } - - return coin, nil -} - -func ParseCoins(str string) (types.Coins, error) { - - split := strings.Split(str, ",") - var coins []types.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 -} - func Query(tmAddr string, key []byte) (*abci.ResponseQuery, error) { uriClient := client.NewURIClient(tmAddr) tmResult := new(ctypes.TMResult) diff --git a/cmd/commands/utils_test.go b/cmd/commands/utils_test.go index 138afac53..692fec743 100644 --- a/cmd/commands/utils_test.go +++ b/cmd/commands/utils_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/tendermint/basecoin/types" ) func TestHex(t *testing.T) { @@ -22,39 +21,4 @@ func TestHex(t *testing.T) { assert.False(isHex(str), "isHex shouldn't identify non-hex string") assert.False(isHex(strWPrefix), "isHex shouldn't identify non-hex string with 0x prefix") assert.True(StripHex(hexWPrefix) == hexNoPrefix, "StripHex doesn't remove first two characters") - -} - -//Test the parse coin and parse coins functionality -func TestParse(t *testing.T) { - assert := assert.New(t) - - makeCoin := func(str string) types.Coin { - coin, err := ParseCoin(str) - if err != nil { - panic(err.Error()) - } - return coin - } - - makeCoins := func(str string) types.Coins { - coin, err := ParseCoins(str) - if err != nil { - panic(err.Error()) - } - return coin - } - - //testing ParseCoin Function - assert.Equal(types.Coin{}, makeCoin(""), "parseCoin makes bad empty coin") - assert.Equal(types.Coin{"fooCoin", 1}, makeCoin("1fooCoin"), "parseCoin makes bad coins") - assert.Equal(types.Coin{"barCoin", 10}, makeCoin("10 barCoin"), "parseCoin makes bad coins") - - //testing ParseCoins Function - assert.True(types.Coins{{"fooCoin", 1}}.IsEqual(makeCoins("1fooCoin")), - "parseCoins doesn't parse a single coin") - assert.True(types.Coins{{"barCoin", 99}, {"fooCoin", 1}}.IsEqual(makeCoins("99barCoin,1fooCoin")), - "parseCoins doesn't properly parse two coins") - assert.True(types.Coins{{"barCoin", 99}, {"fooCoin", 1}}.IsEqual(makeCoins("99 barCoin, 1 fooCoin")), - "parseCoins doesn't properly parse two coins which use spaces") } diff --git a/state/execution_test.go b/state/execution_test.go index b6e09d379..b3daa068c 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -8,131 +8,61 @@ import ( abci "github.com/tendermint/abci/types" "github.com/tendermint/basecoin/types" - "github.com/tendermint/go-crypto" ) -//States and Stores for tests -var ( - store types.KVStore - state *State - accsFoo, accsBar, accsFooBar, accsDup []types.PrivAccount - chainID string = "test_chain_id" -) - -func makeAccs(secrets []string) (accs []types.PrivAccount) { - - for _, secret := range secrets { - privAcc := types.PrivAccountFromSecret(secret) - privAcc.Account.Balance = types.Coins{{"mycoin", 1000}} - accs = append(accs, privAcc) - } - return accs -} - -func acc2State(accs []types.PrivAccount) { - for _, acc := range accs { - state.SetAccount(acc.Account.PubKey.Address(), &acc.Account) - } -} - -//each tx input signs the tx bytes -func signSend(tx *types.SendTx, accs []types.PrivAccount) { - signBytes := tx.SignBytes(chainID) - for i, _ := range tx.Inputs { - tx.Inputs[i].Signature = crypto.SignatureS{accs[i].Sign(signBytes)} - } -} - -//turn a list of accounts into basic list of transaction inputs -func accs2TxInputs(accs []types.PrivAccount) []types.TxInput { - var txs []types.TxInput - for _, acc := range accs { - tx := types.NewTxInput( - acc.Account.PubKey, - types.Coins{{"mycoin", 5}}, - 1) - txs = append(txs, tx) - } - return txs -} - -//turn a list of accounts into basic list of transaction outputs -func accs2TxOutputs(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 -} - -//reset the store/state/Inputs -func reset() { - accsFoo = makeAccs([]string{"foo"}) - accsBar = makeAccs([]string{"bar"}) - accsFooBar = makeAccs([]string{"foo", "bar"}) - accsDup = makeAccs([]string{"foo", "foo", "foo"}) - - store = types.NewMemKVStore() - state = NewState(store) - state.SetChainID(chainID) -} - func TestGetInputs(t *testing.T) { assert := assert.New(t) + et := newExecTest() //nil submissions - reset() acc, res := getInputs(nil, nil) - assert.False(res.IsErr(), "getInputs: error on nil submission") + assert.True(res.IsOK(), "getInputs: error on nil submission") assert.Zero(len(acc), "getInputs: accounts returned on nil submission") //test getInputs for registered, non-registered account - reset() - txs := accs2TxInputs(accsFoo) - _, res = getInputs(state, txs) - assert.True(res.IsErr(), "getInputs: expected to getInput from registered Input") + et.reset() + txs := types.Accs2TxInputs(et.accsFoo, 1) + acc, res = getInputs(et.state, txs) + assert.True(res.IsErr(), "getInputs: expected error when using getInput with non-registered Input") - acc2State(accsFoo) - _, res = getInputs(state, txs) - assert.False(res.IsErr(), "getInputs: expected to getInput from registered Input") + et.acc2State(et.accsFoo) + acc, res = getInputs(et.state, txs) + assert.True(res.IsOK(), "getInputs: expected to getInput from registered Input") //test sending duplicate accounts - reset() - acc2State(accsDup) - txs = accs2TxInputs(accsDup) - _, res = getInputs(state, txs) + et.reset() + et.acc2State(et.accsDup) + txs = types.Accs2TxInputs(et.accsDup, 1) + acc, res = getInputs(et.state, txs) assert.True(res.IsErr(), "getInputs: expected error when sending duplicate accounts") } func TestGetOrMakeOutputs(t *testing.T) { assert := assert.New(t) + et := newExecTest() //nil submissions - reset() acc, res := getOrMakeOutputs(nil, nil, nil) - assert.False(res.IsErr(), "getOrMakeOutputs: error on nil submission") + assert.True(res.IsOK(), "getOrMakeOutputs: error on nil submission") assert.Zero(len(acc), "getOrMakeOutputs: accounts returned on nil submission") //test sending duplicate accounts - reset() - txs := accs2TxOutputs(accsDup) - _, res = getOrMakeOutputs(state, nil, txs) + et.reset() + txs := types.Accs2TxOutputs(et.accsDup) + _, res = getOrMakeOutputs(et.state, nil, txs) assert.True(res.IsErr(), "getOrMakeOutputs: expected error when sending duplicate accounts") //test sending to existing/new account account - reset() - txs1 := accs2TxOutputs(accsFoo) - txs2 := accs2TxOutputs(accsBar) + et.reset() + txs1 := types.Accs2TxOutputs(et.accsFoo) + txs2 := types.Accs2TxOutputs(et.accsBar) - acc2State(accsFoo) - _, res = getOrMakeOutputs(state, nil, txs1) - assert.False(res.IsErr(), "getOrMakeOutputs: error when sending to existing account") + et.acc2State(et.accsFoo) + _, res = getOrMakeOutputs(et.state, nil, txs1) + assert.True(res.IsOK(), "getOrMakeOutputs: error when sending to existing account") - mapRes2, res := getOrMakeOutputs(state, nil, txs2) - assert.False(res.IsErr(), "getOrMakeOutputs: error when sending to new account") + mapRes2, res := getOrMakeOutputs(et.state, nil, txs2) + assert.True(res.IsOK(), "getOrMakeOutputs: error when sending to new account") //test the map results _, map2ok := mapRes2[string(txs2[0].Address)] @@ -142,12 +72,12 @@ func TestGetOrMakeOutputs(t *testing.T) { func TestValidateInputsBasic(t *testing.T) { assert := assert.New(t) + et := newExecTest() //validate input basic - reset() - txs := accs2TxInputs(accsFoo) + txs := types.Accs2TxInputs(et.accsFoo, 1) res := validateInputsBasic(txs) - assert.False(res.IsErr(), fmt.Sprintf("validateInputsBasic: expected no error on good tx input. Error: %v", res.Error())) + assert.True(res.IsOK(), fmt.Sprintf("validateInputsBasic: expected no error on good tx input. Error: %v", res.Error())) txs[0].Coins[0].Amount = 0 res = validateInputsBasic(txs) @@ -157,77 +87,68 @@ func TestValidateInputsBasic(t *testing.T) { func TestValidateInputsAdvanced(t *testing.T) { assert := assert.New(t) - //validate inputs advanced - reset() - txs := types.SendTx{ - Gas: 0, - Fee: types.Coin{"mycoin", 1}, - Inputs: accs2TxInputs(accsFooBar), - Outputs: accs2TxOutputs(accsBar), - } + et := newExecTest() - acc2State(accsFooBar) - accMap, res := getInputs(state, txs.Inputs) - assert.False(res.IsErr(), fmt.Sprintf("validateInputsAdvanced: error retrieving accMap. Error: %v", res.Error())) - signBytes := txs.SignBytes(chainID) + //validate inputs advanced + txs := et.getTx(1, et.accsFooBar) + + et.acc2State(et.accsFooBar) + accMap, res := getInputs(et.state, txs.Inputs) + assert.True(res.IsOK(), fmt.Sprintf("validateInputsAdvanced: error retrieving accMap. Error: %v", res.Error())) + signBytes := txs.SignBytes(et.chainID) //test bad case, unsigned totalCoins, res := validateInputsAdvanced(accMap, signBytes, txs.Inputs) assert.True(res.IsErr(), "validateInputsAdvanced: expected an error on an unsigned tx input") //test good case sgined - signSend(&txs, accsFooBar) + et.signTx(txs, et.accsFooBar) totalCoins, res = validateInputsAdvanced(accMap, signBytes, txs.Inputs) - assert.False(res.IsErr(), fmt.Sprintf("validateInputsAdvanced: expected no error on good tx input. Error: %v", res.Error())) + assert.True(res.IsOK(), fmt.Sprintf("validateInputsAdvanced: expected no error on good tx input. Error: %v", res.Error())) assert.True(totalCoins.IsEqual(txs.Inputs[0].Coins.Plus(txs.Inputs[1].Coins)), "ValidateInputsAdvanced: transaction total coins are not equal") } func TestValidateInputAdvanced(t *testing.T) { assert := assert.New(t) + et := newExecTest() //validate input advanced - reset() - txs := types.SendTx{ - Gas: 0, - Fee: types.Coin{"mycoin", 1}, - Inputs: accs2TxInputs(accsFooBar), - Outputs: accs2TxOutputs(accsBar), - } + txs := et.getTx(1, et.accsFooBar) - acc2State(accsFooBar) - signBytes := txs.SignBytes(chainID) + et.acc2State(et.accsFooBar) + signBytes := txs.SignBytes(et.chainID) //unsigned case - res := validateInputAdvanced(&accsFooBar[0].Account, signBytes, txs.Inputs[0]) + res := validateInputAdvanced(&et.accsFooBar[0].Account, signBytes, txs.Inputs[0]) assert.True(res.IsErr(), "validateInputAdvanced: expected error on tx input without signature") //good signed case - signSend(&txs, accsFooBar) - res = validateInputAdvanced(&accsFooBar[0].Account, signBytes, txs.Inputs[0]) - assert.False(res.IsErr(), fmt.Sprintf("validateInputAdvanced: expected no error on good tx input. Error: %v", res.Error())) + et.signTx(txs, et.accsFooBar) + res = validateInputAdvanced(&et.accsFooBar[0].Account, signBytes, txs.Inputs[0]) + assert.True(res.IsOK(), fmt.Sprintf("validateInputAdvanced: expected no error on good tx input. Error: %v", res.Error())) //bad sequence case - accsFooBar[0].Sequence = 2 - signSend(&txs, accsFooBar) - res = validateInputAdvanced(&accsFooBar[0].Account, signBytes, txs.Inputs[0]) + et.accsFooBar[0].Sequence = 2 + et.signTx(txs, et.accsFooBar) + res = validateInputAdvanced(&et.accsFooBar[0].Account, signBytes, txs.Inputs[0]) assert.True(res.IsErr(), "validateInputAdvanced: expected error on tx input with bad sequence") - accsFooBar[0].Account.Sequence = 1 //restore sequence + et.accsFooBar[0].Account.Sequence = 1 //restore sequence //bad balance case - accsFooBar[1].Balance = types.Coins{{"mycoin", 2}} - signSend(&txs, accsFooBar) - res = validateInputAdvanced(&accsFooBar[0].Account, signBytes, txs.Inputs[0]) + et.accsFooBar[1].Balance = types.Coins{{"mycoin", 2}} + et.signTx(txs, et.accsFooBar) + res = validateInputAdvanced(&et.accsFooBar[0].Account, signBytes, txs.Inputs[0]) assert.True(res.IsErr(), "validateInputAdvanced: expected error on tx input with insufficient funds") } func TestValidateOutputsAdvanced(t *testing.T) { assert := assert.New(t) + et := newExecTest() //validateOutputsBasic - reset() - txs := accs2TxOutputs(accsFoo) + txs := types.Accs2TxOutputs(et.accsFoo) res := validateOutputsBasic(txs) - assert.False(res.IsErr(), fmt.Sprintf("validateOutputsBasic: expected no error on good tx input. Error: %v", res.Error())) + assert.True(res.IsOK(), fmt.Sprintf("validateOutputsBasic: expected no error on good tx input. Error: %v", res.Error())) txs[0].Coins[0].Amount = 0 res = validateOutputsBasic(txs) @@ -236,34 +157,34 @@ func TestValidateOutputsAdvanced(t *testing.T) { func TestSumOutput(t *testing.T) { assert := assert.New(t) + et := newExecTest() //SumOutput - reset() - txs := accs2TxOutputs(accsFooBar) + txs := types.Accs2TxOutputs(et.accsFooBar) total := sumOutputs(txs) assert.True(total.IsEqual(txs[0].Coins.Plus(txs[1].Coins)), "sumOutputs: total coins are not equal") } func TestAdjustBy(t *testing.T) { assert := assert.New(t) + et := newExecTest() //adjustByInputs/adjustByOutputs //sending transaction from Foo to Bar - reset() - initBalFoo := accsFooBar[0].Account.Balance - initBalBar := accsFooBar[1].Account.Balance - acc2State(accsFooBar) + initBalFoo := et.accsFooBar[0].Account.Balance + initBalBar := et.accsFooBar[1].Account.Balance + et.acc2State(et.accsFooBar) - txIn := accs2TxInputs(accsFoo) - txOut := accs2TxOutputs(accsBar) - accMap, _ := getInputs(state, txIn) - accMap, _ = getOrMakeOutputs(state, accMap, txOut) + txIn := types.Accs2TxInputs(et.accsFoo, 1) + txOut := types.Accs2TxOutputs(et.accsBar) + accMap, _ := getInputs(et.state, txIn) + accMap, _ = getOrMakeOutputs(et.state, accMap, txOut) - adjustByInputs(state, accMap, txIn) - adjustByOutputs(state, accMap, txOut, false) + adjustByInputs(et.state, accMap, txIn) + adjustByOutputs(et.state, accMap, txOut, false) - endBalFoo := accMap[string(accsFooBar[0].Account.PubKey.Address())].Balance - endBalBar := accMap[string(accsFooBar[1].Account.PubKey.Address())].Balance + endBalFoo := accMap[string(et.accsFooBar[0].Account.PubKey.Address())].Balance + endBalBar := accMap[string(et.accsFooBar[1].Account.PubKey.Address())].Balance decrBalFoo := initBalFoo.Minus(endBalFoo) incrBalBar := endBalBar.Minus(initBalBar) @@ -276,54 +197,95 @@ func TestAdjustBy(t *testing.T) { func TestExecTx(t *testing.T) { assert := assert.New(t) + et := newExecTest() //ExecTx - reset() - txs := &types.SendTx{ - Gas: 0, - Fee: types.Coin{"mycoin", 1}, - Inputs: accs2TxInputs(accsFoo), - Outputs: accs2TxOutputs(accsBar), - } - - acc2State(accsFoo) - acc2State(accsBar) - signSend(txs, accsFoo) - - exec := func(checkTx bool) (ExecTxRes abci.Result, foo, fooExp, bar, barExp types.Coins) { - 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) - } + txs := et.getTx(1, et.accsFoo) + et.acc2State(et.accsFoo) + et.acc2State(et.accsBar) + et.signTx(txs, et.accsFoo) //Bad Balance - accsFoo[0].Balance = types.Coins{{"mycoin", 2}} - acc2State(accsFoo) - res, _, _, _, _ := exec(true) + et.accsFoo[0].Balance = types.Coins{{"mycoin", 2}} + et.acc2State(et.accsFoo) + res, _, _, _, _ := et.exec(txs, 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) + res, foo, fooexp, bar, barexp := et.exec(txs, false) assert.True(res.IsErr(), fmt.Sprintf("ExecTx/Bad DeliverTx: Expected error return from ExecTx, returned: %v", res)) assert.False(foo.IsEqual(fooexp), fmt.Sprintf("ExecTx/Bad DeliverTx: shouldn't be equal, foo: %v, fooExp: %v", foo, fooexp)) assert.False(bar.IsEqual(barexp), fmt.Sprintf("ExecTx/Bad DeliverTx: shouldn't be equal, bar: %v, barExp: %v", bar, barexp)) //Regular CheckTx - reset() - acc2State(accsFoo) - acc2State(accsBar) - res, _, _, _, _ = exec(true) + et.reset() + et.acc2State(et.accsFoo) + et.acc2State(et.accsBar) + res, _, _, _, _ = et.exec(txs, true) assert.True(res.IsOK(), fmt.Sprintf("ExecTx/Good CheckTx: Expected OK return from ExecTx, Error: %v", res)) //Regular DeliverTx - reset() - acc2State(accsFoo) - acc2State(accsBar) - res, foo, fooexp, bar, barexp = exec(false) + et.reset() + et.acc2State(et.accsFoo) + et.acc2State(et.accsBar) + res, foo, fooexp, bar, barexp = et.exec(txs, 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)) - +} + +/////////////////////////////////////////////////////////////////// + +type execTest struct { + chainID string + store types.KVStore + state *State + accsFoo []types.PrivAccount + accsBar []types.PrivAccount + accsFooBar []types.PrivAccount + accsDup []types.PrivAccount +} + +func newExecTest() *execTest { + et := &execTest{ + chainID: "test_chain_id", + } + et.reset() + return et +} + +func (et *execTest) signTx(tx *types.SendTx, accsIn []types.PrivAccount) { + types.SignTx(et.chainID, tx, accsIn) +} + +func (et *execTest) getTx(seq int, accsIn []types.PrivAccount) *types.SendTx { + return types.GetTx(seq, accsIn, et.accsBar) +} + +func (et *execTest) exec(tx *types.SendTx, checkTx bool) (res abci.Result, foo, fooExp, bar, barExp types.Coins) { + initBalFoo := et.state.GetAccount(et.accsFoo[0].Account.PubKey.Address()).Balance + initBalBar := et.state.GetAccount(et.accsBar[0].Account.PubKey.Address()).Balance + + res = ExecTx(et.state, nil, tx, checkTx, nil) + + endBalFoo := et.state.GetAccount(et.accsFoo[0].Account.PubKey.Address()).Balance + endBalBar := et.state.GetAccount(et.accsBar[0].Account.PubKey.Address()).Balance + decrBalFooExp := tx.Outputs[0].Coins.Plus(types.Coins{tx.Fee}) + return res, endBalFoo, initBalFoo.Minus(decrBalFooExp), endBalBar, initBalBar.Plus(tx.Outputs[0].Coins) +} + +func (et *execTest) acc2State(accs []types.PrivAccount) { + for _, acc := range accs { + et.state.SetAccount(acc.Account.PubKey.Address(), &acc.Account) + } +} + +//reset the store/et.state/Inputs +func (et *execTest) reset() { + et.accsFoo = types.MakeAccs("foo") + et.accsBar = types.MakeAccs("bar") + et.accsFooBar = types.MakeAccs("foo", "bar") + et.accsDup = types.MakeAccs("foo", "foo", "foo") + + et.store = types.NewMemKVStore() + et.state = NewState(et.store) + et.state.SetChainID(et.chainID) } diff --git a/state/state_test.go b/state/state_test.go index ead7e25e4..1d35f2c4f 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -84,7 +84,7 @@ func TestState(t *testing.T) { assert.True(storeHasAll(store), "store doesn't retrieve after CacheSync") //Test Commit on state with non-merkle store - assert.False(state.Commit().IsOK(), "Commit shouldn't work with non-merkle store") + assert.True(state.Commit().IsErr(), "Commit shouldn't work with non-merkle store") //Test CacheWrap with merkleeyes client store useEyesCli() diff --git a/tests/tmsp/tmsp_test.go b/tests/tmsp/tmsp_test.go index eec105ded..86b4bfbf2 100644 --- a/tests/tmsp/tmsp_test.go +++ b/tests/tmsp/tmsp_test.go @@ -57,7 +57,7 @@ func TestSendTx(t *testing.T) { txBytes := wire.BinaryBytes(types.TxS{tx}) res := bcApp.DeliverTx(txBytes) // t.Log(res) - assert.False(t, res.IsErr(), "Failed: %v", res.Error()) + assert.True(t, res.IsOK(), "Failed: %v", res.Error()) } func TestSequence(t *testing.T) { @@ -108,11 +108,11 @@ func TestSequence(t *testing.T) { // Write request txBytes := wire.BinaryBytes(struct{ types.Tx }{tx}) res := bcApp.DeliverTx(txBytes) - assert.False(t, res.IsErr(), "DeliverTx error: %v", res.Error()) + assert.True(t, res.IsOK(), "DeliverTx error: %v", res.Error()) } res := bcApp.Commit() - assert.False(t, res.IsErr(), "Failed Commit: %v", res.Error()) + assert.True(t, res.IsOK(), "Failed Commit: %v", res.Error()) t.Log("-------------------- RANDOM SENDS --------------------") @@ -152,6 +152,6 @@ func TestSequence(t *testing.T) { // Write request txBytes := wire.BinaryBytes(struct{ types.Tx }{tx}) res := bcApp.DeliverTx(txBytes) - assert.False(t, res.IsErr(), "DeliverTx error: %v", res.Error()) + assert.True(t, res.IsOK(), "DeliverTx error: %v", res.Error()) } } diff --git a/types/coin.go b/types/coin.go index 51c33ebc4..1af65edca 100644 --- a/types/coin.go +++ b/types/coin.go @@ -2,6 +2,8 @@ package types import ( "fmt" + "regexp" + "strconv" "strings" ) @@ -11,8 +13,27 @@ type Coin struct { } func (coin Coin) String() string { - return fmt.Sprintf("(%v %v)", - coin.Denom, coin.Amount) + 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 } //---------------------------------------- @@ -22,11 +43,29 @@ type Coins []Coin func (coins Coins) String() string { out := "" for _, coin := range coins { - out += fmt.Sprintf("(%v %v) ", coin.Denom, coin.Amount) + out += fmt.Sprintf("%v,", coin.String()) } return out } +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) { diff --git a/types/coin_test.go b/types/coin_test.go index 3512eb836..5de483a32 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestCoins(t *testing.T) { @@ -53,3 +54,33 @@ func TestCoins(t *testing.T) { 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") +} diff --git a/types/test_helpers.go b/types/test_helpers.go index c7ce21ff0..070c4b739 100644 --- a/types/test_helpers.go +++ b/types/test_helpers.go @@ -43,3 +43,56 @@ func RandAccounts(num int, minAmount int64, maxAmount int64) []PrivAccount { return privAccs } + +///////////////////////////////////////////////////////////////// + +func MakeAccs(secrets ...string) (accs []PrivAccount) { + for _, secret := range secrets { + privAcc := PrivAccountFromSecret(secret) + privAcc.Account.Balance = Coins{{"mycoin", 7}} + accs = append(accs, privAcc) + } + return +} + +func Accs2TxInputs(accs []PrivAccount, seq int) []TxInput { + var txs []TxInput + for _, acc := range accs { + tx := NewTxInput( + acc.Account.PubKey, + Coins{{"mycoin", 5}}, + seq) + txs = append(txs, tx) + } + return txs +} + +//turn a list of accounts into basic list of transaction outputs +func Accs2TxOutputs(accs []PrivAccount) []TxOutput { + var txs []TxOutput + for _, acc := range accs { + tx := TxOutput{ + acc.Account.PubKey.Address(), + Coins{{"mycoin", 4}}} + txs = append(txs, tx) + } + return txs +} + +func GetTx(seq int, accsIn, accsOut []PrivAccount) *SendTx { + txs := &SendTx{ + Gas: 0, + Fee: Coin{"mycoin", 1}, + Inputs: Accs2TxInputs(accsIn, seq), + Outputs: Accs2TxOutputs(accsOut), + } + + return txs +} + +func SignTx(chainID string, tx *SendTx, accs []PrivAccount) { + signBytes := tx.SignBytes(chainID) + for i, _ := range tx.Inputs { + tx.Inputs[i].Signature = crypto.SignatureS{accs[i].Sign(signBytes)} + } +}