Skip to content

Commit

Permalink
added CLI, more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rigelrozanski committed Feb 3, 2017
1 parent 2930f51 commit f6375fe
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 119 deletions.
107 changes: 107 additions & 0 deletions cmd/paytovote/commands/p2vCommands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package commands

import (
"fmt"

bcmd "github.com/tendermint/basecoin/cmd/basecoin/commands"
"github.com/tendermint/basecoin/plugins/paytovote"
"github.com/tendermint/basecoin/types"
"github.com/urfave/cli"
)

const PaytovoteName = "paytovote"

var (
//common flag
IssueFlag = cli.StringFlag{
Name: "issue",
Value: "default issue",
Usage: "name of the issue to generate or vote for",
}

//createIssue flags
VoteFeeCoinFlag = cli.StringFlag{
Name: "voteFeeCoin",
Value: "",
Usage: "the fee's coin type to vote for the issue",
}
VoteFeeAmtFlag = cli.IntFlag{
Name: "voteFeeAmt",
Value: 0,
Usage: "the fee amount of coin type VoteCoinFlag to vote for the issue",
}

//vote flag
VoteForFlag = cli.BoolFlag{
Name: "voteFor",
Usage: "set to true when vote be cast is a vote-for the issue, false if vote-against",
}
)

var (
P2VCreateIssueCmd = cli.Command{
Name: "P2VCreateIssue",
Usage: "Create an issue which can be voted for",
Action: func(c *cli.Context) error {
return cmdCreateIssue(c)
},
Flags: []cli.Flag{
IssueFlag,
VoteFeeCoinFlag,
VoteFeeAmtFlag,
},
}

P2VVoteCmd = cli.Command{
Name: "P2VVote",
Usage: "Vote for an existing issue",
Action: func(c *cli.Context) error {
return cmdVote(c)
},
Flags: []cli.Flag{
IssueFlag,
VoteForFlag,
},
}

PaytovotePluginFlag = cli.BoolFlag{
Name: "paytovote-plugin",
Usage: "Enable the paytovote plugin",
}
)

func init() {
bcmd.RegisterTxPlugin(P2VCreateIssueCmd)
bcmd.RegisterTxPlugin(P2VVoteCmd)
bcmd.RegisterStartPlugin(PaytovotePluginFlag,
func() types.Plugin { return paytovote.New() })
}

func cmdCreateIssue(c *cli.Context) error {
issue := c.String(IssueFlag.Name)
feeCoin := c.String(VoteFeeCoinFlag.Name)
feeAmt := int64(c.Int(VoteFeeAmtFlag.Name))

voteFee := types.Coins{{feeCoin, feeAmt}}
createIssueFee := types.Coins{{"issueToken", 1}} //manually set the cost to create a new issue

txBytes := paytovote.NewCreateIssueTxBytes(issue, voteFee, createIssueFee)

fmt.Println("Issue creation transaction sent")
return bcmd.AppTx(c.Parent(), PaytovoteName, txBytes)
}

func cmdVote(c *cli.Context) error {
issue := c.String(IssueFlag.Name)
voteFor := c.Bool(VoteForFlag.Name)

var voteTB byte = paytovote.TypeByteVoteFor
if !voteFor {
voteTB = paytovote.TypeByteVoteAgainst
}

txBytes := paytovote.NewVoteTxBytes(issue, voteTB)

fmt.Println("Vote transaction sent")
return bcmd.AppTx(c.Parent(), PaytovoteName, txBytes)
}
13 changes: 13 additions & 0 deletions cmd/paytovote/data/genesis.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
"base/chainID", "mint_chain_id",
"mint/add", "D397BC62B435F3CF50570FBAB4340FE52C60858F",
"base/account", {
"pub_key": [1, "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF"],
"coins": [
{
"denom": "blank",
"amount": 1000
}
]
}
]
17 changes: 17 additions & 0 deletions cmd/paytovote/data/priv_validator.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"address": "D397BC62B435F3CF50570FBAB4340FE52C60858F",
"last_height": 0,
"last_round": 0,
"last_signature": null,
"last_signbytes": "",
"last_step": 0,
"priv_key": [
1,
"39E75AA1CF7BC710585977EFC375CD1730519186BD231478C339F2819C3C26E7B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF"
],
"pub_key": [
1,
"B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF"
]
}

16 changes: 16 additions & 0 deletions cmd/paytovote/data/priv_validator2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"address": "4793A333846E5104C46DD9AB9A00E31821B2F301",
"last_height": 0,
"last_round": 0,
"last_signature": null,
"last_signbytes": "",
"last_step": 0,
"priv_key": [
1,
"13A04A552ABAA2CCFA1F618CF9C97F1FD59FC3EE4968FE87DF3637C9B0F2FAAA93766F08BE7135E78DBFFA76B61BC7C52B96256EB4394A224B4EF8BCC954DE2E"
],
"pub_key": [
1,
"93766F08BE7135E78DBFFA76B61BC7C52B96256EB4394A224B4EF8BCC954DE2E"
]
}
16 changes: 16 additions & 0 deletions cmd/paytovote/desc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# paytovote plugin

### Description
paytovote is a basic application which demonstrates how to leverage the basecoin library to create an instance of the basecoin system which utilizes a custom paytovote plugin. The premise of this plugin is to allow users to pay a fee to create or vote for user-specified issues. Unique fees are applied when voting or creating a new issue. Fees may use coin types (for example "voteTokens" or "newIssueTokens"). Currently, the fee to cast a vote is decided by the user when the issue is being generated, and the fee to create a new issue is defined globally within the plugin CLI commands (cmd/paytovote/commands)

### Usage
- enable the paytovote plugin and start `paytovote start --paytovote-plugin`
- start tendermint in another terminal `tendermint node`
- create issues with `paytovote AppTx P2VCreateIssue`
- for a complete list of required flags and usage see:
- `paytovote AppTx -h`
- `paytovote AppTx P2VCreateIssue -h`
- vote for issues with `paytovote AppTx P2VVote`
- for a complete list of required flags and usage see:
- `paytovote AppTx -h`
- `paytovote AppTx P2VVote -h`
60 changes: 18 additions & 42 deletions cmd/paytovote/main.go
Original file line number Diff line number Diff line change
@@ -1,51 +1,27 @@
package main

import (
"flag"
"os"

"github.com/tendermint/abci/server"
"github.com/tendermint/basecoin/app"
"github.com/tendermint/basecoin/plugins/counter"
"github.com/tendermint/basecoin/plugins/paytovote"
cmn "github.com/tendermint/go-common"
eyes "github.com/tendermint/merkleeyes/client"
"github.com/tendermint/basecoin/cmd/basecoin/commands"
_ "github.com/tendermint/basecoin/cmd/paytovote/commands"
"github.com/urfave/cli"
)

func main() {
addrPtr := flag.String("address", "tcp://0.0.0.0:46658", "Listen address")
genFilePath := flag.String("genesis", "", "Genesis file, if any")
flag.Parse()

// Connect to MerkleEyes
eyesCli := eyes.NewLocalClient("", 0) //non-persistent instance of merkleeyes

// Create Basecoin app
app := app.NewBasecoin(eyesCli)

// create/add plugins
counter := counter.New("counter")
paytovote := paytovote.New()
app.RegisterPlugin(counter)
app.RegisterPlugin(paytovote)

// If genesis file was specified, set key-value options
if *genFilePath != "" {
err := app.LoadGenesis(*genFilePath)
if err != nil {
cmn.Exit(cmn.Fmt("%+v", err))
}
app := cli.NewApp()
app.Name = "paytovote"
app.Usage = "paytovote [command] [args...]"
app.Version = "0.1.0"
app.Commands = []cli.Command{
commands.StartCmd,
commands.SendTxCmd,
commands.AppTxCmd,
commands.IbcCmd,
commands.QueryCmd,
commands.VerifyCmd,
commands.BlockCmd,
commands.AccountCmd,
}

// Start the listener
svr, err := server.NewServer(*addrPtr, "socket", app)
if err != nil {
cmn.Exit("create listener: " + err.Error())
}

// Wait forever
cmn.TrapSignal(func() {
// Cleanup
svr.Stop()
})

app.Run(os.Args)
}
22 changes: 0 additions & 22 deletions plugins/paytovote/description.md

This file was deleted.

75 changes: 28 additions & 47 deletions plugins/paytovote/paytovote.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,28 @@ func newP2VIssue(issue string, feePerVote types.Coins) P2VIssue {
}
}

func (p2v *P2VPlugin) IssueKey(issue string) []byte {
func IssueKey(issue string) []byte {
//The state key is defined as only being affected by effected issue
// aka. if multiple paytovote plugins are initialized
// then all will have access to the same issue vote counts
return []byte(fmt.Sprintf("P2VPlugin{issue=%v}.State", issue))
}

func getIssue(store types.KVStore, issue string) (p2vIssue P2VIssue, err error) {
p2vIssueBytes := store.Get(IssueKey(issue))

//Determine if the issue already exists and load
if len(p2vIssueBytes) > 0 { //is there a record of the issue existing?
err = wire.ReadBinaryBytes(p2vIssueBytes, &p2vIssue)
if err != nil {
err = abci.ErrInternalError.AppendLog("Error decoding state: " + err.Error())
}
} else {
err = abci.ErrInternalError.AppendLog("Tx Issue not found")
}
return
}

///////////////////////////////////////////////////

func (p2v *P2VPlugin) Name() string {
Expand Down Expand Up @@ -128,33 +143,10 @@ 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() {
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)

}
}

Expand Down Expand Up @@ -183,20 +175,16 @@ func (p2v *P2VPlugin) runTxCreateIssue(store types.KVStore, ctx types.CallContex
return abci.ErrInsufficientFunds.AppendLog("Tx Funds insufficient for creating a new issue")
}

// Load P2VIssue
var p2vIssue P2VIssue
p2vIssueBytes := store.Get(p2v.IssueKey(tx.Issue))

//Return if the issue already exists
if len(p2vIssueBytes) > 0 {
return abci.ErrInsufficientFunds.AppendLog("Cannot create an already existing issue")
//Return if the issue already exists, aka no error was thrown
if _, err := getIssue(store, tx.Issue); err == nil {
return abci.ErrInternalError.AppendLog("Cannot create an already existing issue")
}

// Create and Save P2VIssue, charge fee, return
newP2VIssue := newP2VIssue(tx.Issue, tx.FeePerVote)
store.Set(p2v.IssueKey(tx.Issue), wire.BinaryBytes(newP2VIssue))
store.Set(IssueKey(tx.Issue), wire.BinaryBytes(newP2VIssue))
chargeFee(store, ctx, tx.Fee2CreateIssue)
return abci.NewResultOK(wire.BinaryBytes(p2vIssue), "")
return abci.OK
}

func (p2v *P2VPlugin) runTxVote(store types.KVStore, ctx types.CallContext, txBytes []byte) (res abci.Result) {
Expand All @@ -214,17 +202,9 @@ func (p2v *P2VPlugin) runTxVote(store types.KVStore, ctx types.CallContext, txBy
}

// Load P2VIssue
var p2vIssue P2VIssue
p2vIssueBytes := store.Get(p2v.IssueKey(tx.Issue))

//Determine if the issue already exists and load
if len(p2vIssueBytes) > 0 { //is there a record of the issue existing?
err = wire.ReadBinaryBytes(p2vIssueBytes, &p2vIssue)
if err != nil {
return abci.ErrInternalError.AppendLog("Error decoding state: " + err.Error())
}
} else {
return abci.ErrInsufficientFunds.AppendLog("Tx Issue not found")
p2vIssue, err := getIssue(store, tx.Issue)
if err != nil {
return abci.ErrInternalError.AppendLog("error loading issue: " + err.Error())
}

// Did the caller provide enough coins?
Expand All @@ -239,13 +219,14 @@ func (p2v *P2VPlugin) runTxVote(store types.KVStore, ctx types.CallContext, txBy
case TypeByteVoteAgainst:
p2vIssue.votesAgainst += 1
default:
return abci.ErrInternalError.AppendLog("P2VTx.ActionTypeByte was not recognized")
return abci.ErrInternalError.AppendLog("P2VTx.VoteTypeByte was not recognized")
}

fmt.Println(p2vIssue.votesFor)
// Save P2VIssue, charge fee, return
store.Set(p2v.IssueKey(tx.Issue), wire.BinaryBytes(p2vIssue))
store.Set(IssueKey(tx.Issue), wire.BinaryBytes(p2vIssue))
chargeFee(store, ctx, p2vIssue.FeePerVote)
return abci.NewResultOK(wire.BinaryBytes(p2vIssue), "")
return abci.OK
}

func (p2v *P2VPlugin) InitChain(store types.KVStore, vals []*abci.Validator) {}
Expand Down
Loading

0 comments on commit f6375fe

Please sign in to comment.