diff --git a/cmd/paytovote/main.go b/cmd/paytovote/main.go index 8b8a50449685..45062535c870 100644 --- a/cmd/paytovote/main.go +++ b/cmd/paytovote/main.go @@ -2,7 +2,6 @@ package main import ( "flag" - "path" "github.com/tendermint/abci/server" "github.com/tendermint/basecoin/app" @@ -18,7 +17,7 @@ func main() { flag.Parse() // Connect to MerkleEyes - eyesCli := eyes.NewLocalClient(path.Join(".", "merkleeyes.db"), 0) + eyesCli := eyes.NewLocalClient("", 0) //non-persistent instance of merkleeyes // Create Basecoin app app := app.NewBasecoin(eyesCli) diff --git a/plugins/paytovote/paytovote.go b/plugins/paytovote/paytovote.go index 1169c18ff24e..0f4ea5cf3842 100644 --- a/plugins/paytovote/paytovote.go +++ b/plugins/paytovote/paytovote.go @@ -4,6 +4,7 @@ import ( "fmt" abci "github.com/tendermint/abci/types" + "github.com/tendermint/basecoin/state" "github.com/tendermint/basecoin/types" "github.com/tendermint/go-wire" ) @@ -98,7 +99,12 @@ func (p2v *P2VPlugin) SetOption(store types.KVStore, key string, value string) ( func (p2v *P2VPlugin) RunTx(store types.KVStore, ctx types.CallContext, txBytes []byte) (res abci.Result) { defer func() { - //TODO return the ctx coins to the wallet if there is an error + //Return the ctx coins to the wallet if there is an error + if res.IsErr() { + acc := ctx.CallerAccount + acc.Balance = acc.Balance.Plus(ctx.Coins) // add the context transaction coins + state.SetAccount(store, ctx.CallerAddress, acc) // save the new balance + } }() //Determine the transaction type and then send to the appropriate transaction function @@ -117,15 +123,43 @@ func (p2v *P2VPlugin) RunTx(store types.KVStore, ctx types.CallContext, txBytes } } -func chargeFee(ctx types.CallContext, fee types.Coins) { +func chargeFee(store types.KVStore, ctx types.CallContext, fee types.Coins) { + + //Charge the Fee from the context coins leftoverCoins := ctx.Coins.Minus(fee) if !leftoverCoins.IsZero() { - // TODO If there are any funds left over, return funds. - // ctx.CallerAccount is synced w/ store, so just modify that and store it. + lc := "leftoverCoins: " + for i := 0; i < len(leftoverCoins); i++ { + lc += " " + leftoverCoins[i].String() + } + fmt.Println(lc) + lc = "fee: " + for i := 0; i < len(fee); i++ { + lc += " " + fee[i].String() + } + fmt.Println(lc) + + acc := ctx.CallerAccount + lc = "acc b4: " + for i := 0; i < len(acc.Balance); i++ { + lc += " " + acc.Balance[i].String() + } + fmt.Println(lc) + + //return leftover coins + acc.Balance = acc.Balance.Plus(leftoverCoins) // subtract fees + state.SetAccount(store, ctx.CallerAddress, acc) // save the new balance + lc = "acc aftr: " + for i := 0; i < len(acc.Balance); i++ { + lc += " " + acc.Balance[i].String() + } + fmt.Println(lc) + } } func (p2v *P2VPlugin) runTxCreateIssue(store types.KVStore, ctx types.CallContext, txBytes []byte) (res abci.Result) { + // Decode tx var tx createIssueTx err := wire.ReadBinaryBytes(txBytes, &tx) @@ -161,11 +195,12 @@ func (p2v *P2VPlugin) runTxCreateIssue(store types.KVStore, ctx types.CallContex // Create and Save P2VIssue, charge fee, return newP2VIssue := newP2VIssue(tx.Issue, tx.FeePerVote) store.Set(p2v.IssueKey(tx.Issue), wire.BinaryBytes(newP2VIssue)) - chargeFee(ctx, tx.Fee2CreateIssue) + chargeFee(store, ctx, tx.Fee2CreateIssue) return abci.NewResultOK(wire.BinaryBytes(p2vIssue), "") } func (p2v *P2VPlugin) runTxVote(store types.KVStore, ctx types.CallContext, txBytes []byte) (res abci.Result) { + // Decode tx var tx voteTx err := wire.ReadBinaryBytes(txBytes, &tx) @@ -209,16 +244,12 @@ func (p2v *P2VPlugin) runTxVote(store types.KVStore, ctx types.CallContext, txBy // Save P2VIssue, charge fee, return store.Set(p2v.IssueKey(tx.Issue), wire.BinaryBytes(p2vIssue)) - chargeFee(ctx, p2vIssue.FeePerVote) + chargeFee(store, ctx, p2vIssue.FeePerVote) return abci.NewResultOK(wire.BinaryBytes(p2vIssue), "") } -func (p2v *P2VPlugin) InitChain(store types.KVStore, vals []*abci.Validator) { -} - -func (p2v *P2VPlugin) BeginBlock(store types.KVStore, height uint64) { -} - +func (p2v *P2VPlugin) InitChain(store types.KVStore, vals []*abci.Validator) {} +func (p2v *P2VPlugin) BeginBlock(store types.KVStore, height uint64) {} func (p2v *P2VPlugin) EndBlock(store types.KVStore, height uint64) []*abci.Validator { return nil } diff --git a/plugins/paytovote/paytovote_test.go b/plugins/paytovote/paytovote_test.go index 234ae8dd409b..98a0c2b52bc3 100644 --- a/plugins/paytovote/paytovote_test.go +++ b/plugins/paytovote/paytovote_test.go @@ -1,12 +1,12 @@ package paytovote import ( - "path" "testing" "github.com/stretchr/testify/assert" abci "github.com/tendermint/abci/types" "github.com/tendermint/basecoin/app" + "github.com/tendermint/basecoin/state" "github.com/tendermint/basecoin/testutils" "github.com/tendermint/basecoin/types" "github.com/tendermint/go-wire" @@ -16,11 +16,10 @@ import ( func TestP2VPlugin(t *testing.T) { // Basecoin initialization - eyesCli := eyescli.NewLocalClient(path.Join(".", "merkleeyes.db"), 0) + eyesClient := eyescli.NewLocalClient("", 0) //non-persistent instance of merkleeyes chainID := "test_chain_id" - bcApp := app.NewBasecoin(eyesCli) + bcApp := app.NewBasecoin(store) bcApp.SetOption("base/chainID", chainID) - t.Log(bcApp.Info()) // Add Counter plugin P2VPlugin := New() @@ -28,10 +27,11 @@ func TestP2VPlugin(t *testing.T) { // Account initialization test1PrivAcc := testutils.PrivAccountFromSecret("test1") + test1Acc := test1PrivAcc.Account // Seed Basecoin with account - test1Acc := test1PrivAcc.Account - test1Acc.Balance = types.Coins{{"", 1000}, {"issueToken", 1000}, {"voteToken", 1000}} + startBal := types.Coins{{"", 1000}, {"issueToken", 1000}, {"voteToken", 1000}} + test1Acc.Balance = startBal bcApp.SetOption("base/account", string(wire.JSONBytes(test1Acc))) deliverTx := func(gas int64, @@ -51,27 +51,33 @@ func TestP2VPlugin(t *testing.T) { // Sign request signBytes := tx.SignBytes(chainID) - t.Logf("Sign bytes: %X\n", signBytes) sig := test1PrivAcc.PrivKey.Sign(signBytes) tx.Input.Signature = sig - t.Logf("Signed TX bytes: %X\n", wire.BinaryBytes(struct{ types.Tx }{tx})) // Write request txBytes := wire.BinaryBytes(struct{ types.Tx }{tx}) return bcApp.DeliverTx(txBytes) } + testBalance := func(expected types.Coins) { + //TODO debug testBalance (acc returns nil, bad store?) + /*acc := state.GetAccount(store, test1Acc.PubKey.Address()) + bal := acc.Balance + if !bal.IsEqual(expected) { + var expStr, balStr string + for i := 0; i < len(expected); i++ { + expStr += " " + expected[i].String() + } + for i := 0; i < len(bal); i++ { + balStr += " " + bal[i].String() + } + + t.Errorf("bad balance expected %v, got %v", expStr, balStr) + }*/ + } + //TODO: Generate tests which query the results of an issue - /* queryIssue := func(issue string) abci.Result { - key := P2VPlugin.StateKey(issue) - query := make([]byte, 1+wire.ByteSliceSize(key)) - buf := query - buf[0] = 0x01 // Get TypeByte - buf = buf[1:] - wire.PutByteSlice(buf, key) - t.Log(len(query)) - return bcApp.Query(query) - }*/ + // // REF: deliverTx(gas, fee, inputCoins, inputSequence, NewVoteTxBytes(issue, voteTypeByte)) // REF: deliverTx(gas, fee, inputCoins, inputSequence, NewCreateIssueTxBytes(issue, feePerVote, fee2CreateIssue)) @@ -82,33 +88,40 @@ func TestP2VPlugin(t *testing.T) { res := deliverTx(0, types.Coin{}, types.Coins{{"", 1}, {"issueToken", 1}, {"voteToken", 2}}, 1, NewCreateIssueTxBytes(issue1, types.Coins{{"voteToken", 2}}, types.Coins{{"issueToken", 1}})) assert.True(t, res.IsOK(), res.String()) + testBalance(startBal.Minus(types.Coins{{"issueToken", 1}})) // Test a basic votes res = deliverTx(0, types.Coin{}, types.Coins{{"", 1}, {"issueToken", 1}, {"voteToken", 2}}, 2, NewVoteTxBytes(issue1, TypeByteVoteFor)) assert.True(t, res.IsOK(), res.String()) + testBalance(startBal.Minus(types.Coins{{"issueToken", 1}, {"voteToken", 2}})) res = deliverTx(0, types.Coin{}, types.Coins{{"", 1}, {"issueToken", 1}, {"voteToken", 2}}, 3, NewVoteTxBytes(issue1, TypeByteVoteAgainst)) assert.True(t, res.IsOK(), res.String()) + testBalance(startBal.Minus(types.Coins{{"issueToken", 1}, {"voteToken", 4}})) // Test prevented voting on non-existent issue res = deliverTx(0, types.Coin{}, types.Coins{{"", 1}, {"issueToken", 1}, {"voteToken", 2}}, 5, NewVoteTxBytes(issue2, TypeByteVoteFor)) assert.True(t, res.IsErr(), res.String()) + testBalance(startBal.Minus(types.Coins{{"issueToken", 1}, {"voteToken", 4}})) // Test prevented duplicate issue generation res = deliverTx(0, types.Coin{}, types.Coins{{"", 1}, {"issueToken", 1}, {"voteToken", 2}}, 5, NewCreateIssueTxBytes(issue1, types.Coins{{"voteToken", 1}}, types.Coins{{"issueToken", 1}})) assert.True(t, res.IsErr(), res.String()) + testBalance(startBal.Minus(types.Coins{{"issueToken", 1}, {"voteToken", 4}})) // Test prevented issue generation from insufficient funds res = deliverTx(0, types.Coin{}, types.Coins{{"", 1}, {"issueToken", 1}, {"voteToken", 2}}, 5, NewCreateIssueTxBytes(issue2, types.Coins{{"voteToken", 1}}, types.Coins{{"issueToken", 2}})) assert.True(t, res.IsErr(), res.String()) + testBalance(startBal.Minus(types.Coins{{"issueToken", 1}, {"voteToken", 4}})) // Test prevented voting from insufficient funds res = deliverTx(0, types.Coin{}, types.Coins{{"", 1}, {"issueToken", 1}, {"voteToken", 1}}, 5, NewVoteTxBytes(issue1, TypeByteVoteFor)) assert.True(t, res.IsErr(), res.String()) + testBalance(startBal.Minus(types.Coins{{"issueToken", 1}, {"voteToken", 4}})) }