diff --git a/Makefile b/Makefile index 893fe21c0..d22c6561d 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ install: test: go test --race `${NOVENDOR}` - go run tests/tmsp/*.go + #go run tests/tendermint/*.go get_deps: go get -d github.com/tendermint/basecoin/... diff --git a/app/app.go b/app/app.go index 98fcee879..c4e596473 100644 --- a/app/app.go +++ b/app/app.go @@ -17,9 +17,11 @@ const ( PluginTypeByteBase = 0x01 PluginTypeByteEyes = 0x02 + PluginTypeByteVote = 0x03 PluginNameBase = "base" PluginNameEyes = "eyes" + PluginNameVote = "vote" ) type Basecoin struct { @@ -45,6 +47,10 @@ func (app *Basecoin) Info() string { return Fmt("Basecoin v%v", version) } +func (app *Basecoin) RegisterPlugin(typeByte byte, name string, plugin types.Plugin) { + app.plugins.RegisterPlugin(typeByte, name, plugin) +} + // TMSP::SetOption func (app *Basecoin) SetOption(key string, value string) (log string) { PluginName, key := splitKey(key) diff --git a/tests/tmsp/main.go b/app/tmsp_test.go similarity index 62% rename from tests/tmsp/main.go rename to app/tmsp_test.go index eea1cbe80..611075853 100644 --- a/tests/tmsp/main.go +++ b/app/tmsp_test.go @@ -1,36 +1,29 @@ -package main +package app import ( - "fmt" + "testing" - "github.com/tendermint/basecoin/app" - "github.com/tendermint/basecoin/tests" + cmn "github.com/tendermint/basecoin/common" "github.com/tendermint/basecoin/types" . "github.com/tendermint/go-common" - "github.com/tendermint/go-crypto" "github.com/tendermint/go-wire" eyescli "github.com/tendermint/merkleeyes/client" ) -func main() { - testSendTx() - testSequence() -} - -func testSendTx() { +func TestSendTx(t *testing.T) { eyesCli := eyescli.NewLocalClient() chainID := "test_chain_id" - bcApp := app.NewBasecoin(eyesCli) + bcApp := NewBasecoin(eyesCli) bcApp.SetOption("base/chainID", chainID) - fmt.Println(bcApp.Info()) + t.Log(bcApp.Info()) - test1PrivAcc := tests.PrivAccountFromSecret("test1") - test2PrivAcc := tests.PrivAccountFromSecret("test2") + test1PrivAcc := cmn.PrivAccountFromSecret("test1") + test2PrivAcc := cmn.PrivAccountFromSecret("test2") // Seed Basecoin with account test1Acc := test1PrivAcc.Account test1Acc.Balance = types.Coins{{"", 1000}} - fmt.Println(bcApp.SetOption("base/account", string(wire.JSONBytes(test1Acc)))) + t.Log(bcApp.SetOption("base/account", string(wire.JSONBytes(test1Acc)))) res := bcApp.Commit() if res.IsErr() { @@ -42,7 +35,7 @@ func testSendTx() { Fee: 0, Gas: 0, Inputs: []types.TxInput{ - makeInput(test1PrivAcc.Account.PubKey, types.Coins{{"", 1}}, 1), + cmn.MakeInput(test1PrivAcc.Account.PubKey, types.Coins{{"", 1}}, 1), }, Outputs: []types.TxOutput{ types.TxOutput{ @@ -54,42 +47,41 @@ func testSendTx() { // Sign request signBytes := tx.SignBytes(chainID) - fmt.Printf("Sign bytes: %X\n", signBytes) + t.Log("Sign bytes: %X\n", signBytes) sig := test1PrivAcc.PrivKey.Sign(signBytes) tx.Inputs[0].Signature = sig - //fmt.Println("tx:", tx) - fmt.Printf("Signed TX bytes: %X\n", wire.BinaryBytes(struct{ types.Tx }{tx})) + t.Log("Signed TX bytes: %X\n", wire.BinaryBytes(struct{ types.Tx }{tx})) // Write request txBytes := wire.BinaryBytes(struct{ types.Tx }{tx}) res = bcApp.AppendTx(txBytes) - fmt.Println(res) + t.Log(res) if res.IsErr() { - Exit(Fmt("Failed: %v", res.Error())) + t.Errorf(Fmt("Failed: %v", res.Error())) } } -func testSequence() { +func TestSequence(t *testing.T) { eyesCli := eyescli.NewLocalClient() chainID := "test_chain_id" - bcApp := app.NewBasecoin(eyesCli) + bcApp := NewBasecoin(eyesCli) bcApp.SetOption("base/chainID", chainID) - fmt.Println(bcApp.Info()) + t.Log(bcApp.Info()) // Get the test account - test1PrivAcc := tests.PrivAccountFromSecret("test1") + test1PrivAcc := cmn.PrivAccountFromSecret("test1") test1Acc := test1PrivAcc.Account test1Acc.Balance = types.Coins{{"", 1 << 53}} - fmt.Println(bcApp.SetOption("base/account", string(wire.JSONBytes(test1Acc)))) + t.Log(bcApp.SetOption("base/account", string(wire.JSONBytes(test1Acc)))) res := bcApp.Commit() if res.IsErr() { - Exit(Fmt("Failed Commit: %v", res.Error())) + t.Errorf(Fmt("Failed Commit: %v", res.Error())) } sequence := int(1) // Make a bunch of PrivAccounts - privAccounts := tests.RandAccounts(1000, 1000000, 0) + privAccounts := cmn.RandAccounts(1000, 1000000, 0) privAccountSequences := make(map[string]int) // Send coins to each account @@ -100,7 +92,7 @@ func testSequence() { Fee: 2, Gas: 2, Inputs: []types.TxInput{ - makeInput(test1Acc.PubKey, types.Coins{{"", 1000002}}, sequence), + cmn.MakeInput(test1Acc.PubKey, types.Coins{{"", 1000002}}, sequence), }, Outputs: []types.TxOutput{ types.TxOutput{ @@ -115,22 +107,22 @@ func testSequence() { signBytes := tx.SignBytes(chainID) sig := test1PrivAcc.PrivKey.Sign(signBytes) tx.Inputs[0].Signature = sig - // fmt.Printf("ADDR: %X -> %X\n", tx.Inputs[0].Address, tx.Outputs[0].Address) + // t.Log("ADDR: %X -> %X\n", tx.Inputs[0].Address, tx.Outputs[0].Address) // Write request txBytes := wire.BinaryBytes(struct{ types.Tx }{tx}) res := bcApp.AppendTx(txBytes) if res.IsErr() { - Exit("AppendTx error: " + res.Error()) + t.Errorf("AppendTx error: " + res.Error()) } } - fmt.Println("-------------------- RANDOM SENDS --------------------") + t.Log("-------------------- RANDOM SENDS --------------------") res = bcApp.Commit() if res.IsErr() { - Exit(Fmt("Failed Commit: %v", res.Error())) + t.Errorf(Fmt("Failed Commit: %v", res.Error())) } // Now send coins between these accounts @@ -150,7 +142,7 @@ func testSequence() { Fee: 2, Gas: 2, Inputs: []types.TxInput{ - makeInput(privAccountA.Account.PubKey, types.Coins{{"", 3}}, privAccountASequence+1), + cmn.MakeInput(privAccountA.Account.PubKey, types.Coins{{"", 3}}, privAccountASequence+1), }, Outputs: []types.TxOutput{ types.TxOutput{ @@ -164,26 +156,13 @@ func testSequence() { signBytes := tx.SignBytes(chainID) sig := privAccountA.PrivKey.Sign(signBytes) tx.Inputs[0].Signature = sig - // fmt.Printf("ADDR: %X -> %X\n", tx.Inputs[0].Address, tx.Outputs[0].Address) + // t.Log("ADDR: %X -> %X\n", tx.Inputs[0].Address, tx.Outputs[0].Address) // Write request txBytes := wire.BinaryBytes(struct{ types.Tx }{tx}) res := bcApp.AppendTx(txBytes) if res.IsErr() { - Exit("AppendTx error: " + res.Error()) + t.Errorf("AppendTx error: " + res.Error()) } } } - -func makeInput(pubKey crypto.PubKey, coins types.Coins, sequence int) types.TxInput { - input := types.TxInput{ - Address: pubKey.Address(), - PubKey: pubKey, - Coins: coins, - Sequence: sequence, - } - if sequence > 1 { - input.PubKey = nil - } - return input -} diff --git a/tests/common.go b/common/testing.go similarity index 73% rename from tests/common.go rename to common/testing.go index 1a9f3aee3..918494e60 100644 --- a/tests/common.go +++ b/common/testing.go @@ -1,4 +1,5 @@ -package tests +//functions used in testing throughout +package common import ( "github.com/tendermint/basecoin/types" @@ -44,3 +45,17 @@ func RandAccounts(num int, minAmount int64, maxAmount int64) []types.PrivAccount return privAccs } + +//make input term for the AppTx or SendTx Types +func MakeInput(pubKey crypto.PubKey, coins types.Coins, sequence int) types.TxInput { + input := types.TxInput{ + Address: pubKey.Address(), + PubKey: pubKey, + Coins: coins, + Sequence: sequence, + } + if sequence > 1 { + input.PubKey = nil + } + return input +} diff --git a/plugins/vote/vote.go b/plugins/vote/vote.go new file mode 100644 index 000000000..3f75e3447 --- /dev/null +++ b/plugins/vote/vote.go @@ -0,0 +1,92 @@ +package vote + +import ( + "github.com/tendermint/basecoin/types" + "github.com/tendermint/go-wire" + tmsp "github.com/tendermint/tmsp/types" +) + +type Vote struct { + bb *ballotBox +} + +type ballotBox struct { + issue string + votesYes int + votesNo int +} + +type Tx struct { + voteYes bool +} + +func NewVoteInstance(issue string) Vote { + return Vote{ + &ballotBox{ + issue: issue, + votesYes: 0, + votesNo: 0, + }, + } +} + +func (app Vote) SetOption(store types.KVStore, key string, value string) (log string) { + return "" +} + +//because no coins are being exchanged ctx is unused +func (app Vote) RunTx(store types.KVStore, ctx types.CallContext, txBytes []byte) (res tmsp.Result) { + + // Decode tx + var tx Tx + err := wire.ReadBinaryBytes(txBytes, &tx) + if err != nil { + return tmsp.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error()) + } + + //Read the ballotBox from the store + kvBytes := store.Get([]byte(app.bb.issue)) + var tempBB ballotBox + + //does the issue already exist? + if kvBytes != nil { + err := wire.ReadBinaryBytes(kvBytes, &tempBB) + if err != nil { + return tmsp.ErrBaseEncodingError.AppendLog("Error decoding BallotBox: " + err.Error()) + } + } else { + + //TODO add extra fee for opening new issue + + tempBB = ballotBox{ + issue: app.bb.issue, + votesYes: 0, + votesNo: 0, + } + issueBytes := wire.BinaryBytes(struct{ ballotBox }{tempBB}) + store.Set([]byte(app.bb.issue), issueBytes) + } + + //Write the updated ballotBox to the store + if tx.voteYes { + tempBB.votesYes += 1 + } else { + tempBB.votesNo += 1 + } + issueBytes := wire.BinaryBytes(struct{ ballotBox }{tempBB}) + store.Set([]byte(app.bb.issue), issueBytes) + + return tmsp.OK +} + +//unused +func (app Vote) InitChain(store types.KVStore, vals []*tmsp.Validator) { +} + +func (app Vote) BeginBlock(store types.KVStore, height uint64) { +} + +func (app Vote) EndBlock(store types.KVStore, height uint64) []*tmsp.Validator { + var diffs []*tmsp.Validator + return diffs +} diff --git a/plugins/vote/vote_test.go b/plugins/vote/vote_test.go new file mode 100644 index 000000000..c2cce6f3a --- /dev/null +++ b/plugins/vote/vote_test.go @@ -0,0 +1,100 @@ +package vote + +import ( + "fmt" + "testing" + + "github.com/tendermint/basecoin/app" + cmn "github.com/tendermint/basecoin/common" + "github.com/tendermint/basecoin/types" + . "github.com/tendermint/go-common" + "github.com/tendermint/go-wire" + eyescli "github.com/tendermint/merkleeyes/client" +) + +func TestVote(t *testing.T) { + //base initialization + eyesCli := eyescli.NewLocalClient() + chainID := "test_chain_id" + bcApp := app.NewBasecoin(eyesCli) + bcApp.SetOption("base/chainID", chainID) + fmt.Println(bcApp.Info()) + + //account initialization + test1PrivAcc := cmn.PrivAccountFromSecret("test1") + + // Seed Basecoin with account + test1Acc := test1PrivAcc.Account + test1Acc.Balance = types.Coins{{"", 1000}} + fmt.Println(bcApp.SetOption("base/account", string(wire.JSONBytes(test1Acc)))) + + //vote initialization + votePlugin := NewVoteInstance("humanRights") + var typeByte byte = app.PluginTypeByteVote + bcApp.RegisterPlugin( + typeByte, + app.PluginNameVote, + votePlugin, + ) + + //commit + res := bcApp.Commit() + if res.IsErr() { + Exit(Fmt("Failed Commit: %v", res.Error())) + } + + //transaction sequence number + seqNum := 1 + + //Construct, Sign, Write function variable + CSW := func(fees, sendCoins int64) { + // Construct an AppTx signature + tx := &types.AppTx{ + Fee: fees, + Gas: 0, + Type: typeByte, + Input: cmn.MakeInput(test1Acc.PubKey, types.Coins{{"", sendCoins}}, seqNum), + Data: wire.BinaryBytes(struct{ Tx }{Tx{voteYes: true}}), //a vote for human rights + } + + // Sign request + signBytes := tx.SignBytes(chainID) + fmt.Printf("Sign bytes: %X\n", signBytes) + sig := test1PrivAcc.PrivKey.Sign(signBytes) + tx.Input.Signature = sig + fmt.Printf("Signed TX bytes: %X\n", wire.BinaryBytes(struct{ types.Tx }{tx})) + + // Write request + txBytes := wire.BinaryBytes(struct{ types.Tx }{tx}) + res = bcApp.AppendTx(txBytes) + fmt.Println(res) + + if res.IsOK() { + seqNum += 1 + } + } + + //Test a basic send, no fees + CSW(0, 1) + if res.IsErr() { + Exit(Fmt("Failed: %v", res.Error())) + } + + //Test fee prevented transaction + CSW(2, 1) + if res.IsOK() { + Exit(Fmt("expected bad transaction")) + } + + //Test equal fees + CSW(2, 2) + if res.IsErr() { + Exit(Fmt("Failed: %v", res.Error())) + } + + //Test more send coins than fees + CSW(2, 3) + if res.IsErr() { + Exit(Fmt("Failed: %v", res.Error())) + } +} diff --git a/tests/tendermint/main.go b/tests/tendermint/main.go index a221d4b00..91ed52e7b 100644 --- a/tests/tendermint/main.go +++ b/tests/tendermint/main.go @@ -5,7 +5,7 @@ import ( "time" "github.com/gorilla/websocket" - "github.com/tendermint/basecoin/tests" + cmn "github.com/tendermint/basecoin/common" "github.com/tendermint/basecoin/types" . "github.com/tendermint/go-common" "github.com/tendermint/go-rpc/client" @@ -37,10 +37,10 @@ func main() { }() // Get the root account - root := tests.PrivAccountFromSecret("test") + root := cmn.PrivAccountFromSecret("test") sequence := int(0) // Make a bunch of PrivAccounts - privAccounts := tests.RandAccounts(1000, 1000000, 0) + privAccounts := cmn.RandAccounts(1000, 1000000, 0) privAccountSequences := make(map[string]int) // Send coins to each account