Vote->Counter; Fee is types.Coin; Context has Account; Cleanup
This commit is contained in:
parent
5ba8250efd
commit
16a6680e24
10
app/app.go
10
app/app.go
|
@ -41,8 +41,8 @@ func (app *Basecoin) Info() abci.ResponseInfo {
|
|||
return abci.ResponseInfo{Data: Fmt("Basecoin v%v", version)}
|
||||
}
|
||||
|
||||
func (app *Basecoin) RegisterPlugin(name string, plugin types.Plugin) {
|
||||
app.plugins.RegisterPlugin(name, plugin)
|
||||
func (app *Basecoin) RegisterPlugin(plugin types.Plugin) {
|
||||
app.plugins.RegisterPlugin(plugin)
|
||||
}
|
||||
|
||||
// TMSP::SetOption
|
||||
|
@ -144,21 +144,21 @@ func (app *Basecoin) Commit() (res abci.Result) {
|
|||
// TMSP::InitChain
|
||||
func (app *Basecoin) InitChain(validators []*abci.Validator) {
|
||||
for _, plugin := range app.plugins.GetList() {
|
||||
plugin.Plugin.InitChain(app.state, validators)
|
||||
plugin.InitChain(app.state, validators)
|
||||
}
|
||||
}
|
||||
|
||||
// TMSP::BeginBlock
|
||||
func (app *Basecoin) BeginBlock(height uint64) {
|
||||
for _, plugin := range app.plugins.GetList() {
|
||||
plugin.Plugin.BeginBlock(app.state, height)
|
||||
plugin.BeginBlock(app.state, height)
|
||||
}
|
||||
}
|
||||
|
||||
// TMSP::EndBlock
|
||||
func (app *Basecoin) EndBlock(height uint64) (diffs []*abci.Validator) {
|
||||
for _, plugin := range app.plugins.GetList() {
|
||||
moreDiffs := plugin.Plugin.EndBlock(app.state, height)
|
||||
moreDiffs := plugin.EndBlock(app.state, height)
|
||||
diffs = append(diffs, moreDiffs...)
|
||||
}
|
||||
return
|
||||
|
|
|
@ -3,9 +3,9 @@ package app
|
|||
import (
|
||||
"testing"
|
||||
|
||||
cmn "github.com/tendermint/basecoin/common"
|
||||
"github.com/tendermint/basecoin/testutils"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
. "github.com/tendermint/go-common"
|
||||
cmn "github.com/tendermint/go-common"
|
||||
"github.com/tendermint/go-wire"
|
||||
eyescli "github.com/tendermint/merkleeyes/client"
|
||||
)
|
||||
|
@ -17,8 +17,8 @@ func TestSendTx(t *testing.T) {
|
|||
bcApp.SetOption("base/chainID", chainID)
|
||||
t.Log(bcApp.Info())
|
||||
|
||||
test1PrivAcc := cmn.PrivAccountFromSecret("test1")
|
||||
test2PrivAcc := cmn.PrivAccountFromSecret("test2")
|
||||
test1PrivAcc := testutils.PrivAccountFromSecret("test1")
|
||||
test2PrivAcc := testutils.PrivAccountFromSecret("test2")
|
||||
|
||||
// Seed Basecoin with account
|
||||
test1Acc := test1PrivAcc.Account
|
||||
|
@ -27,15 +27,15 @@ func TestSendTx(t *testing.T) {
|
|||
|
||||
res := bcApp.Commit()
|
||||
if res.IsErr() {
|
||||
Exit(Fmt("Failed Commit: %v", res.Error()))
|
||||
cmn.Exit(cmn.Fmt("Failed Commit: %v", res.Error()))
|
||||
}
|
||||
|
||||
// Construct a SendTx signature
|
||||
tx := &types.SendTx{
|
||||
Fee: 0,
|
||||
Gas: 0,
|
||||
Fee: types.Coin{"", 0},
|
||||
Inputs: []types.TxInput{
|
||||
cmn.MakeInput(test1PrivAcc.Account.PubKey, types.Coins{{"", 1}}, 1),
|
||||
types.NewTxInput(test1PrivAcc.Account.PubKey, types.Coins{{"", 1}}, 1),
|
||||
},
|
||||
Outputs: []types.TxOutput{
|
||||
types.TxOutput{
|
||||
|
@ -57,7 +57,7 @@ func TestSendTx(t *testing.T) {
|
|||
res = bcApp.DeliverTx(txBytes)
|
||||
t.Log(res)
|
||||
if res.IsErr() {
|
||||
t.Errorf(Fmt("Failed: %v", res.Error()))
|
||||
t.Errorf("Failed: %v", res.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,19 +69,19 @@ func TestSequence(t *testing.T) {
|
|||
t.Log(bcApp.Info())
|
||||
|
||||
// Get the test account
|
||||
test1PrivAcc := cmn.PrivAccountFromSecret("test1")
|
||||
test1PrivAcc := testutils.PrivAccountFromSecret("test1")
|
||||
test1Acc := test1PrivAcc.Account
|
||||
test1Acc.Balance = types.Coins{{"", 1 << 53}}
|
||||
t.Log(bcApp.SetOption("base/account", string(wire.JSONBytes(test1Acc))))
|
||||
|
||||
res := bcApp.Commit()
|
||||
if res.IsErr() {
|
||||
t.Errorf(Fmt("Failed Commit: %v", res.Error()))
|
||||
t.Errorf("Failed Commit: %v", res.Error())
|
||||
}
|
||||
|
||||
sequence := int(1)
|
||||
// Make a bunch of PrivAccounts
|
||||
privAccounts := cmn.RandAccounts(1000, 1000000, 0)
|
||||
privAccounts := testutils.RandAccounts(1000, 1000000, 0)
|
||||
privAccountSequences := make(map[string]int)
|
||||
// Send coins to each account
|
||||
|
||||
|
@ -89,10 +89,10 @@ func TestSequence(t *testing.T) {
|
|||
privAccount := privAccounts[i]
|
||||
|
||||
tx := &types.SendTx{
|
||||
Fee: 2,
|
||||
Gas: 2,
|
||||
Fee: types.Coin{"", 2},
|
||||
Inputs: []types.TxInput{
|
||||
cmn.MakeInput(test1Acc.PubKey, types.Coins{{"", 1000002}}, sequence),
|
||||
types.NewTxInput(test1Acc.PubKey, types.Coins{{"", 1000002}}, sequence),
|
||||
},
|
||||
Outputs: []types.TxOutput{
|
||||
types.TxOutput{
|
||||
|
@ -122,13 +122,13 @@ func TestSequence(t *testing.T) {
|
|||
|
||||
res = bcApp.Commit()
|
||||
if res.IsErr() {
|
||||
t.Errorf(Fmt("Failed Commit: %v", res.Error()))
|
||||
t.Errorf("Failed Commit: %v", res.Error())
|
||||
}
|
||||
|
||||
// Now send coins between these accounts
|
||||
for i := 0; i < 10000; i++ {
|
||||
randA := RandInt() % len(privAccounts)
|
||||
randB := RandInt() % len(privAccounts)
|
||||
randA := cmn.RandInt() % len(privAccounts)
|
||||
randB := cmn.RandInt() % len(privAccounts)
|
||||
if randA == randB {
|
||||
continue
|
||||
}
|
||||
|
@ -139,10 +139,10 @@ func TestSequence(t *testing.T) {
|
|||
privAccountB := privAccounts[randB]
|
||||
|
||||
tx := &types.SendTx{
|
||||
Fee: 2,
|
||||
Gas: 2,
|
||||
Fee: types.Coin{"", 2},
|
||||
Inputs: []types.TxInput{
|
||||
cmn.MakeInput(privAccountA.Account.PubKey, types.Coins{{"", 3}}, privAccountASequence+1),
|
||||
types.NewTxInput(privAccountA.Account.PubKey, types.Coins{{"", 3}}, privAccountASequence+1),
|
||||
},
|
||||
Outputs: []types.TxOutput{
|
||||
types.TxOutput{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
hash: 3869944d14a8df914ffcad02c2ef3548173daba51c5ea697767f8af77c07b348
|
||||
updated: 2017-01-14T20:46:16.999965963-08:00
|
||||
updated: 2017-01-15T14:45:40.368426139-08:00
|
||||
imports:
|
||||
- name: github.com/btcsuite/btcd
|
||||
version: afec1bd1245a4a19e6dfe1306974b733e7cbb9b8
|
||||
|
@ -41,7 +41,7 @@ imports:
|
|||
- leveldb/table
|
||||
- leveldb/util
|
||||
- name: github.com/tendermint/abci
|
||||
version: 6526ab2137fadd0f4d2e25002bbfc1784b4f3c27
|
||||
version: 05096de3687ac582bec63860b3dd384acd9149aa
|
||||
subpackages:
|
||||
- client
|
||||
- server
|
||||
|
@ -68,9 +68,9 @@ imports:
|
|||
- name: github.com/tendermint/go-logger
|
||||
version: cefb3a45c0bf3c493a04e9bcd9b1540528be59f2
|
||||
- name: github.com/tendermint/go-merkle
|
||||
version: 1bc9a24706d715cd45403593c6d0a870d70011bb
|
||||
version: 2979c7eb8aa020fa1cf203654907dbb889703888
|
||||
- name: github.com/tendermint/go-p2p
|
||||
version: eab2baa363de01b052b88c559e803776cd2c7dd6
|
||||
version: 67c9086b7458eb45b1970483decd01cd744c477a
|
||||
subpackages:
|
||||
- upnp
|
||||
- name: github.com/tendermint/go-rpc
|
||||
|
@ -85,12 +85,12 @@ imports:
|
|||
subpackages:
|
||||
- term
|
||||
- name: github.com/tendermint/merkleeyes
|
||||
version: db66769b34a950bb588919c94925724f21583925
|
||||
version: 2cf87e5f049ab6131aa4ea188c1b5b629d9b3bf9
|
||||
subpackages:
|
||||
- app
|
||||
- client
|
||||
- name: github.com/tendermint/tendermint
|
||||
version: 0aecfe2dae3269a9450b5d8b3bac8721a8dde7c7
|
||||
version: cf0cb9558aaecbf3ddb071eb863df77e55d828ed
|
||||
subpackages:
|
||||
- rpc/core/types
|
||||
- types
|
||||
|
@ -131,4 +131,16 @@ imports:
|
|||
- stats
|
||||
- tap
|
||||
- transport
|
||||
testImports: []
|
||||
testImports:
|
||||
- name: github.com/davecgh/go-spew
|
||||
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
|
||||
subpackages:
|
||||
- spew
|
||||
- name: github.com/pmezard/go-difflib
|
||||
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
|
||||
subpackages:
|
||||
- difflib
|
||||
- name: github.com/stretchr/testify
|
||||
version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0
|
||||
subpackages:
|
||||
- assert
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
package counter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
"github.com/tendermint/go-wire"
|
||||
)
|
||||
|
||||
type CounterPluginState struct {
|
||||
Counter int
|
||||
TotalCost types.Coins
|
||||
}
|
||||
|
||||
type CounterTx struct {
|
||||
Valid bool
|
||||
Cost types.Coins
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
type CounterPlugin struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (cp *CounterPlugin) Name() string {
|
||||
return cp.name
|
||||
}
|
||||
|
||||
func (cp *CounterPlugin) StateKey() []byte {
|
||||
return []byte(fmt.Sprintf("CounterPlugin{name=%v}.State", cp.name))
|
||||
}
|
||||
|
||||
func NewCounterPlugin(name string) *CounterPlugin {
|
||||
return &CounterPlugin{
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func (cp *CounterPlugin) SetOption(store types.KVStore, key string, value string) (log string) {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (cp *CounterPlugin) RunTx(store types.KVStore, ctx types.CallContext, txBytes []byte) (res abci.Result) {
|
||||
|
||||
// Decode tx
|
||||
var tx CounterTx
|
||||
err := wire.ReadBinaryBytes(txBytes, &tx)
|
||||
if err != nil {
|
||||
return abci.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error())
|
||||
}
|
||||
|
||||
// Validate tx
|
||||
if !tx.Valid {
|
||||
return abci.ErrInternalError.AppendLog("CounterTx.Valid must be true")
|
||||
}
|
||||
if !tx.Cost.IsValid() {
|
||||
return abci.ErrInternalError.AppendLog("CounterTx.Cost is not sorted or has zero amounts")
|
||||
}
|
||||
if !tx.Cost.IsNonnegative() {
|
||||
return abci.ErrInternalError.AppendLog("CounterTx.Cost must be nonnegative")
|
||||
}
|
||||
|
||||
// Did the caller provide enough coins?
|
||||
if !ctx.Coins.IsGTE(tx.Cost) {
|
||||
return abci.ErrInsufficientFunds.AppendLog("CounterTx.Cost was not provided")
|
||||
}
|
||||
|
||||
// TODO If there are any funds left over, return funds.
|
||||
// e.g. !ctx.Coins.Minus(tx.Cost).IsZero()
|
||||
// ctx.CallerAccount is synced w/ store, so just modify that and store it.
|
||||
|
||||
// Load CounterPluginState
|
||||
var cpState CounterPluginState
|
||||
cpStateBytes := store.Get(cp.StateKey())
|
||||
if len(cpStateBytes) > 0 {
|
||||
err = wire.ReadBinaryBytes(cpStateBytes, &cpState)
|
||||
if err != nil {
|
||||
return abci.ErrInternalError.AppendLog("Error decoding state: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Update CounterPluginState
|
||||
cpState.Counter += 1
|
||||
cpState.TotalCost = cpState.TotalCost.Plus(tx.Cost)
|
||||
|
||||
// Save CounterPluginState
|
||||
store.Set(cp.StateKey(), wire.BinaryBytes(cpState))
|
||||
|
||||
return abci.OK
|
||||
}
|
||||
|
||||
func (cp *CounterPlugin) InitChain(store types.KVStore, vals []*abci.Validator) {
|
||||
}
|
||||
|
||||
func (cp *CounterPlugin) BeginBlock(store types.KVStore, height uint64) {
|
||||
}
|
||||
|
||||
func (cp *CounterPlugin) EndBlock(store types.KVStore, height uint64) []*abci.Validator {
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package counter
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/basecoin/app"
|
||||
"github.com/tendermint/basecoin/testutils"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
"github.com/tendermint/go-wire"
|
||||
eyescli "github.com/tendermint/merkleeyes/client"
|
||||
)
|
||||
|
||||
func TestCounterPlugin(t *testing.T) {
|
||||
|
||||
// Basecoin initialization
|
||||
eyesCli := eyescli.NewLocalClient()
|
||||
chainID := "test_chain_id"
|
||||
bcApp := app.NewBasecoin(eyesCli)
|
||||
bcApp.SetOption("base/chainID", chainID)
|
||||
t.Log(bcApp.Info())
|
||||
|
||||
// Add Counter plugin
|
||||
counterPluginName := "testcounter"
|
||||
counterPlugin := NewCounterPlugin(counterPluginName)
|
||||
bcApp.RegisterPlugin(counterPlugin)
|
||||
|
||||
// Account initialization
|
||||
test1PrivAcc := testutils.PrivAccountFromSecret("test1")
|
||||
|
||||
// Seed Basecoin with account
|
||||
test1Acc := test1PrivAcc.Account
|
||||
test1Acc.Balance = types.Coins{{"", 1000}, {"gold", 1000}}
|
||||
bcApp.SetOption("base/account", string(wire.JSONBytes(test1Acc)))
|
||||
|
||||
// Deliver a CounterTx
|
||||
DeliverCounterTx := func(gas int64, fee types.Coin, inputCoins types.Coins, inputSequence int, cost types.Coins) abci.Result {
|
||||
// Construct an AppTx signature
|
||||
tx := &types.AppTx{
|
||||
Gas: gas,
|
||||
Fee: fee,
|
||||
Name: counterPluginName,
|
||||
Input: types.NewTxInput(test1Acc.PubKey, inputCoins, inputSequence),
|
||||
Data: wire.BinaryBytes(CounterTx{Valid: true, Cost: cost}),
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// REF: DeliverCounterTx(gas, fee, inputCoins, inputSequence, cost) {
|
||||
|
||||
// Test a basic send, no fee
|
||||
res := DeliverCounterTx(0, types.Coin{}, types.Coins{{"", 1}}, 1, types.Coins{})
|
||||
assert.True(t, res.IsOK(), res.String())
|
||||
|
||||
// Test fee prevented transaction
|
||||
res = DeliverCounterTx(0, types.Coin{"", 2}, types.Coins{{"", 1}}, 2, types.Coins{})
|
||||
assert.True(t, res.IsErr(), res.String())
|
||||
|
||||
// Test input equals fee
|
||||
res = DeliverCounterTx(0, types.Coin{"", 2}, types.Coins{{"", 2}}, 2, types.Coins{})
|
||||
assert.True(t, res.IsOK(), res.String())
|
||||
|
||||
// Test more input than fee
|
||||
res = DeliverCounterTx(0, types.Coin{"", 2}, types.Coins{{"", 3}}, 3, types.Coins{})
|
||||
assert.True(t, res.IsOK(), res.String())
|
||||
|
||||
// Test input equals fee+cost
|
||||
res = DeliverCounterTx(0, types.Coin{"", 1}, types.Coins{{"", 3}, {"gold", 1}}, 4, types.Coins{{"", 2}, {"gold", 1}})
|
||||
assert.True(t, res.IsOK(), res.String())
|
||||
|
||||
// Test fee+cost prevented transaction, not enough ""
|
||||
res = DeliverCounterTx(0, types.Coin{"", 1}, types.Coins{{"", 2}, {"gold", 1}}, 5, types.Coins{{"", 2}, {"gold", 1}})
|
||||
assert.True(t, res.IsErr(), res.String())
|
||||
|
||||
// Test fee+cost prevented transaction, not enough "gold"
|
||||
res = DeliverCounterTx(0, types.Coin{"", 1}, types.Coins{{"", 3}, {"gold", 1}}, 5, types.Coins{{"", 2}, {"gold", 2}})
|
||||
assert.True(t, res.IsErr(), res.String())
|
||||
|
||||
// Test more input than fee, more ""
|
||||
res = DeliverCounterTx(0, types.Coin{"", 1}, types.Coins{{"", 4}, {"gold", 1}}, 6, types.Coins{{"", 2}, {"gold", 1}})
|
||||
assert.True(t, res.IsOK(), res.String())
|
||||
|
||||
// Test more input than fee, more "gold"
|
||||
res = DeliverCounterTx(0, types.Coin{"", 1}, types.Coins{{"", 3}, {"gold", 2}}, 7, types.Coins{{"", 2}, {"gold", 1}})
|
||||
assert.True(t, res.IsOK(), res.String())
|
||||
|
||||
// REF: DeliverCounterTx(gas, fee, inputCoins, inputSequence, cost) {
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
package vote
|
||||
|
||||
import (
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
"github.com/tendermint/go-wire"
|
||||
)
|
||||
|
||||
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 abci.Result) {
|
||||
|
||||
// Decode tx
|
||||
var tx Tx
|
||||
err := wire.ReadBinaryBytes(txBytes, &tx)
|
||||
if err != nil {
|
||||
return abci.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 abci.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 abci.OK
|
||||
}
|
||||
|
||||
//unused
|
||||
func (app Vote) InitChain(store types.KVStore, vals []*abci.Validator) {
|
||||
}
|
||||
|
||||
func (app Vote) BeginBlock(store types.KVStore, height uint64) {
|
||||
}
|
||||
|
||||
func (app Vote) EndBlock(store types.KVStore, height uint64) []*abci.Validator {
|
||||
var diffs []*abci.Validator
|
||||
return diffs
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
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"
|
||||
)
|
||||
|
||||
const PluginNameVote = "vote"
|
||||
|
||||
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")
|
||||
bcApp.RegisterPlugin(
|
||||
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,
|
||||
Name: PluginNameVote,
|
||||
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.DeliverTx(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()))
|
||||
}
|
||||
}
|
|
@ -10,8 +10,6 @@ import (
|
|||
// If the tx is invalid, a TMSP error will be returned.
|
||||
func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc events.Fireable) abci.Result {
|
||||
|
||||
// TODO: do something with fees
|
||||
fees := types.Coins{}
|
||||
chainID := state.GetChainID()
|
||||
|
||||
// Exec tx
|
||||
|
@ -46,10 +44,9 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e
|
|||
return res.PrependLog("in validateInputsAdvanced()")
|
||||
}
|
||||
outTotal := sumOutputs(tx.Outputs)
|
||||
if !inTotal.IsEqual(outTotal.Plus(types.Coins{{"", tx.Fee}})) {
|
||||
if !inTotal.IsEqual(outTotal.Plus(types.Coins{tx.Fee})) {
|
||||
return abci.ErrBaseInvalidOutput.AppendLog("Input total != output total + fees")
|
||||
}
|
||||
fees = fees.Plus(types.Coins{{"", tx.Fee}})
|
||||
|
||||
// TODO: Fee validation for SendTx
|
||||
|
||||
|
@ -96,7 +93,7 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e
|
|||
log.Info(Fmt("validateInputAdvanced failed on %X: %v", tx.Input.Address, res))
|
||||
return res.PrependLog("in validateInputAdvanced()")
|
||||
}
|
||||
if !tx.Input.Coins.IsGTE(types.Coins{{"", tx.Fee}}) {
|
||||
if !tx.Input.Coins.IsGTE(types.Coins{tx.Fee}) {
|
||||
log.Info(Fmt("Sender did not send enough to cover the fee %X", tx.Input.Address))
|
||||
return abci.ErrBaseInsufficientFunds
|
||||
}
|
||||
|
@ -109,7 +106,7 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e
|
|||
}
|
||||
|
||||
// Good!
|
||||
coins := tx.Input.Coins.Minus(types.Coins{{"", tx.Fee}})
|
||||
coins := tx.Input.Coins.Minus(types.Coins{tx.Fee})
|
||||
inAcc.Sequence += 1
|
||||
inAcc.Balance = inAcc.Balance.Minus(tx.Input.Coins)
|
||||
|
||||
|
@ -120,13 +117,12 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e
|
|||
}
|
||||
|
||||
// Create inAcc checkpoint
|
||||
inAccDeducted := inAcc.Copy()
|
||||
inAccCopy := inAcc.Copy()
|
||||
|
||||
// Run the tx.
|
||||
// XXX cache := types.NewStateCache(state)
|
||||
cache := state.CacheWrap()
|
||||
cache.SetAccount(tx.Input.Address, inAcc)
|
||||
ctx := types.NewCallContext(tx.Input.Address, coins)
|
||||
ctx := types.NewCallContext(tx.Input.Address, inAcc, coins)
|
||||
res = plugin.RunTx(cache, ctx, tx.Data)
|
||||
if res.IsOK() {
|
||||
cache.CacheSync()
|
||||
|
@ -145,10 +141,10 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e
|
|||
} else {
|
||||
log.Info("AppTx failed", "error", res)
|
||||
// Just return the coins and return.
|
||||
inAccDeducted.Balance = inAccDeducted.Balance.Plus(coins)
|
||||
inAccCopy.Balance = inAccCopy.Balance.Plus(coins)
|
||||
// But take the gas
|
||||
// TODO
|
||||
state.SetAccount(tx.Input.Address, inAccDeducted)
|
||||
state.SetAccount(tx.Input.Address, inAccCopy)
|
||||
}
|
||||
return res
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
cmn "github.com/tendermint/basecoin/common"
|
||||
"github.com/tendermint/basecoin/testutils"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
. "github.com/tendermint/go-common"
|
||||
cmn "github.com/tendermint/go-common"
|
||||
"github.com/tendermint/go-rpc/client"
|
||||
"github.com/tendermint/go-rpc/types"
|
||||
"github.com/tendermint/go-wire"
|
||||
|
@ -21,7 +21,7 @@ func main() {
|
|||
|
||||
_, err := ws.Start()
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
cmn.Exit(err.Error())
|
||||
}
|
||||
var counter = 0
|
||||
|
||||
|
@ -32,15 +32,15 @@ func main() {
|
|||
if !ok {
|
||||
break
|
||||
}
|
||||
fmt.Println(counter, "res:", Blue(string(res)))
|
||||
fmt.Println(counter, "res:", cmn.Blue(string(res)))
|
||||
}
|
||||
}()
|
||||
|
||||
// Get the root account
|
||||
root := cmn.PrivAccountFromSecret("test")
|
||||
root := testutils.PrivAccountFromSecret("test")
|
||||
sequence := int(0)
|
||||
// Make a bunch of PrivAccounts
|
||||
privAccounts := cmn.RandAccounts(1000, 1000000, 0)
|
||||
privAccounts := testutils.RandAccounts(1000, 1000000, 0)
|
||||
privAccountSequences := make(map[string]int)
|
||||
|
||||
// Send coins to each account
|
||||
|
@ -72,12 +72,12 @@ func main() {
|
|||
|
||||
// Write request
|
||||
txBytes := wire.BinaryBytes(struct{ types.Tx }{tx})
|
||||
request := rpctypes.NewRPCRequest("fakeid", "broadcast_tx_sync", Arr(txBytes))
|
||||
request := rpctypes.NewRPCRequest("fakeid", "broadcast_tx_sync", cmn.Arr(txBytes))
|
||||
reqBytes := wire.JSONBytes(request)
|
||||
//fmt.Print(".")
|
||||
err := ws.WriteMessage(websocket.TextMessage, reqBytes)
|
||||
if err != nil {
|
||||
Exit("writing websocket request: " + err.Error())
|
||||
cmn.Exit("writing websocket request: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,8 +86,8 @@ func main() {
|
|||
counter += 1
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
|
||||
randA := RandInt() % len(privAccounts)
|
||||
randB := RandInt() % len(privAccounts)
|
||||
randA := cmn.RandInt() % len(privAccounts)
|
||||
randB := cmn.RandInt() % len(privAccounts)
|
||||
if randA == randB {
|
||||
continue
|
||||
}
|
||||
|
@ -122,12 +122,12 @@ func main() {
|
|||
|
||||
// Write request
|
||||
txBytes := wire.BinaryBytes(struct{ types.Tx }{tx})
|
||||
request := rpctypes.NewRPCRequest("fakeid", "broadcast_tx_sync", Arr(txBytes))
|
||||
request := rpctypes.NewRPCRequest("fakeid", "broadcast_tx_sync", cmn.Arr(txBytes))
|
||||
reqBytes := wire.JSONBytes(request)
|
||||
//fmt.Print(".")
|
||||
err := ws.WriteMessage(websocket.TextMessage, reqBytes)
|
||||
if err != nil {
|
||||
Exit("writing websocket request: " + err.Error())
|
||||
cmn.Exit("writing websocket request: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//functions used in testing throughout
|
||||
package common
|
||||
// Functions used in testing throughout
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"github.com/tendermint/basecoin/types"
|
||||
|
@ -45,17 +45,3 @@ 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
|
||||
}
|
|
@ -128,3 +128,15 @@ func (coins Coins) IsPositive() bool {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (coins Coins) IsNonnegative() bool {
|
||||
if len(coins) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, coinAmount := range coins {
|
||||
if coinAmount.Amount < 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
abci "github.com/tendermint/abci/types"
|
||||
)
|
||||
|
||||
type Plugin interface {
|
||||
Name() string
|
||||
SetOption(store KVStore, key string, value string) (log string)
|
||||
RunTx(store KVStore, ctx CallContext, txBytes []byte) (res abci.Result)
|
||||
InitChain(store KVStore, vals []*abci.Validator)
|
||||
|
@ -12,22 +14,21 @@ type Plugin interface {
|
|||
EndBlock(store KVStore, height uint64) []*abci.Validator
|
||||
}
|
||||
|
||||
type NamedPlugin struct {
|
||||
Name string
|
||||
Plugin
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// CallContext.Caller's coins have been deducted by CallContext.Coins
|
||||
// Caller's Sequence has been incremented.
|
||||
type CallContext struct {
|
||||
Caller []byte
|
||||
Coins Coins
|
||||
CallerAddress []byte
|
||||
CallerAccount *Account
|
||||
Coins Coins
|
||||
}
|
||||
|
||||
func NewCallContext(caller []byte, coins Coins) CallContext {
|
||||
func NewCallContext(callerAddress []byte, callerAccount *Account, coins Coins) CallContext {
|
||||
return CallContext{
|
||||
Caller: caller,
|
||||
Coins: coins,
|
||||
CallerAddress: callerAddress,
|
||||
CallerAccount: callerAccount,
|
||||
Coins: coins,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +36,7 @@ func NewCallContext(caller []byte, coins Coins) CallContext {
|
|||
|
||||
type Plugins struct {
|
||||
byName map[string]Plugin
|
||||
plist []NamedPlugin
|
||||
plist []Plugin
|
||||
}
|
||||
|
||||
func NewPlugins() *Plugins {
|
||||
|
@ -44,18 +45,22 @@ func NewPlugins() *Plugins {
|
|||
}
|
||||
}
|
||||
|
||||
func (pgz *Plugins) RegisterPlugin(name string, plugin Plugin) {
|
||||
func (pgz *Plugins) RegisterPlugin(plugin Plugin) {
|
||||
name := plugin.Name()
|
||||
if name == "" {
|
||||
panic("Plugin name cannot be blank")
|
||||
}
|
||||
if _, exists := pgz.byName[name]; exists {
|
||||
panic(fmt.Sprintf("Plugin already exists by the name of %v", name))
|
||||
}
|
||||
pgz.byName[name] = plugin
|
||||
pgz.plist = append(pgz.plist, NamedPlugin{
|
||||
Name: name,
|
||||
Plugin: plugin,
|
||||
})
|
||||
pgz.plist = append(pgz.plist, plugin)
|
||||
}
|
||||
|
||||
func (pgz *Plugins) GetByName(name string) Plugin {
|
||||
return pgz.byName[name]
|
||||
}
|
||||
|
||||
func (pgz *Plugins) GetList() []NamedPlugin {
|
||||
func (pgz *Plugins) GetList() []Plugin {
|
||||
return pgz.plist
|
||||
}
|
||||
|
|
21
types/tx.go
21
types/tx.go
|
@ -75,6 +75,19 @@ func (txIn TxInput) String() string {
|
|||
return Fmt("TxInput{%X,%v,%v,%v,%v}", txIn.Address, txIn.Coins, txIn.Sequence, txIn.Signature, txIn.PubKey)
|
||||
}
|
||||
|
||||
func NewTxInput(pubKey crypto.PubKey, coins Coins, sequence int) TxInput {
|
||||
input := TxInput{
|
||||
Address: pubKey.Address(),
|
||||
PubKey: pubKey,
|
||||
Coins: coins,
|
||||
Sequence: sequence,
|
||||
}
|
||||
if sequence > 1 {
|
||||
input.PubKey = nil
|
||||
}
|
||||
return input
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
type TxOutput struct {
|
||||
|
@ -102,8 +115,8 @@ func (txOut TxOutput) String() string {
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
type SendTx struct {
|
||||
Fee int64 `json:"fee"` // Fee
|
||||
Gas int64 `json:"gas"` // Gas
|
||||
Fee Coin `json:"fee"` // Fee
|
||||
Inputs []TxInput `json:"inputs"`
|
||||
Outputs []TxOutput `json:"outputs"`
|
||||
}
|
||||
|
@ -133,14 +146,14 @@ func (tx *SendTx) SetSignature(addr []byte, sig crypto.Signature) bool {
|
|||
}
|
||||
|
||||
func (tx *SendTx) String() string {
|
||||
return Fmt("SendTx{%v/%v %v->%v}", tx.Fee, tx.Gas, tx.Inputs, tx.Outputs)
|
||||
return Fmt("SendTx{%v/%v %v->%v}", tx.Gas, tx.Fee, tx.Inputs, tx.Outputs)
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
type AppTx struct {
|
||||
Fee int64 `json:"fee"` // Fee
|
||||
Gas int64 `json:"gas"` // Gas
|
||||
Fee Coin `json:"fee"` // Fee
|
||||
Name string `json:"type"` // Which plugin
|
||||
Input TxInput `json:"input"` // Hmmm do we want coins?
|
||||
Data []byte `json:"data"`
|
||||
|
@ -161,7 +174,7 @@ func (tx *AppTx) SetSignature(sig crypto.Signature) bool {
|
|||
}
|
||||
|
||||
func (tx *AppTx) String() string {
|
||||
return Fmt("AppTx{%v/%v %v %v %X}", tx.Fee, tx.Gas, tx.Name, tx.Input, tx.Data)
|
||||
return Fmt("AppTx{%v/%v %v %v %X}", tx.Gas, tx.Fee, tx.Name, tx.Input, tx.Data)
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -10,8 +10,8 @@ var chainID string = "test_chain"
|
|||
|
||||
func TestSendTxSignable(t *testing.T) {
|
||||
sendTx := &SendTx{
|
||||
Fee: 111,
|
||||
Gas: 222,
|
||||
Fee: Coin{"", 111},
|
||||
Inputs: []TxInput{
|
||||
TxInput{
|
||||
Address: []byte("input1"),
|
||||
|
@ -37,7 +37,7 @@ func TestSendTxSignable(t *testing.T) {
|
|||
}
|
||||
signBytes := sendTx.SignBytes(chainID)
|
||||
signBytesHex := Fmt("%X", signBytes)
|
||||
expected := "010A746573745F636861696E01000000000000006F00000000000000DE01020106696E7075743101010000000000000030390301093200000106696E70757432010100000000000000006F01DE0000010201076F757470757431010100000000000000014D01076F75747075743201010000000000000001BC"
|
||||
expected := "010A746573745F636861696E0100000000000000DE00000000000000006F01020106696E7075743101010000000000000030390301093200000106696E70757432010100000000000000006F01DE0000010201076F757470757431010100000000000000014D01076F75747075743201010000000000000001BC"
|
||||
if signBytesHex != expected {
|
||||
t.Errorf("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signBytesHex)
|
||||
}
|
||||
|
@ -45,8 +45,8 @@ func TestSendTxSignable(t *testing.T) {
|
|||
|
||||
func TestAppTxSignable(t *testing.T) {
|
||||
callTx := &AppTx{
|
||||
Fee: 111,
|
||||
Gas: 222,
|
||||
Fee: Coin{"", 111},
|
||||
Name: "X",
|
||||
Input: TxInput{
|
||||
Address: []byte("input1"),
|
||||
|
@ -57,7 +57,7 @@ func TestAppTxSignable(t *testing.T) {
|
|||
}
|
||||
signBytes := callTx.SignBytes(chainID)
|
||||
signBytesHex := Fmt("%X", signBytes)
|
||||
expected := "010A746573745F636861696E01000000000000006F00000000000000DE0101580106696E70757431010100000000000000303903010932000001056461746131"
|
||||
expected := "010A746573745F636861696E0100000000000000DE00000000000000006F0101580106696E70757431010100000000000000303903010932000001056461746131"
|
||||
if signBytesHex != expected {
|
||||
t.Errorf("Got unexpected sign string for AppTx. Expected:\n%v\nGot:\n%v", expected, signBytesHex)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue