Fix up BasecoinApp and tests
This commit is contained in:
parent
7c4f408934
commit
fc44de2141
26
app/app.go
26
app/app.go
|
@ -1,8 +1,6 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/basecoin"
|
||||
eyes "github.com/tendermint/merkleeyes/client"
|
||||
|
@ -89,8 +87,10 @@ func (app *Basecoin) DeliverTx(txBytes []byte) abci.Result {
|
|||
|
||||
// TODO: can we abstract this setup and commit logic??
|
||||
cache := app.state.CacheWrap()
|
||||
ctx := stack.NewContext(app.state.GetChainID(),
|
||||
app.logger.With("call", "delivertx"))
|
||||
ctx := stack.NewContext(
|
||||
app.state.GetChainID(),
|
||||
app.logger.With("call", "delivertx"),
|
||||
)
|
||||
res, err := app.handler.DeliverTx(ctx, cache, tx)
|
||||
|
||||
if err != nil {
|
||||
|
@ -110,8 +110,10 @@ func (app *Basecoin) CheckTx(txBytes []byte) abci.Result {
|
|||
}
|
||||
|
||||
// TODO: can we abstract this setup and commit logic??
|
||||
ctx := stack.NewContext(app.state.GetChainID(),
|
||||
app.logger.With("call", "checktx"))
|
||||
ctx := stack.NewContext(
|
||||
app.state.GetChainID(),
|
||||
app.logger.With("call", "checktx"),
|
||||
)
|
||||
// checktx generally shouldn't touch the state, but we don't care
|
||||
// here on the framework level, since the cacheState is thrown away next block
|
||||
res, err := app.handler.CheckTx(ctx, app.cacheState, tx)
|
||||
|
@ -176,15 +178,3 @@ func (app *Basecoin) EndBlock(height uint64) (res abci.ResponseEndBlock) {
|
|||
// }
|
||||
return
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// Splits the string at the first '/'.
|
||||
// if there are none, the second string is nil.
|
||||
func splitKey(key string) (prefix string, suffix string) {
|
||||
if strings.Contains(key, "/") {
|
||||
keyParts := strings.SplitN(key, "/", 2)
|
||||
return keyParts[0], keyParts[1]
|
||||
}
|
||||
return key, ""
|
||||
}
|
||||
|
|
109
app/app_test.go
109
app/app_test.go
|
@ -9,7 +9,12 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/modules/coin"
|
||||
"github.com/tendermint/basecoin/stack"
|
||||
"github.com/tendermint/basecoin/txs"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
eyes "github.com/tendermint/merkleeyes/client"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
@ -36,10 +41,17 @@ func newAppTest(t *testing.T) *appTest {
|
|||
}
|
||||
|
||||
// make a tx sending 5mycoin from each accIn to accOut
|
||||
func (at *appTest) getTx(seq int) *types.SendTx {
|
||||
tx := types.MakeSendTx(seq, at.accOut, at.accIn)
|
||||
types.SignTx(at.chainID, tx, at.accIn)
|
||||
return tx
|
||||
func (at *appTest) getTx(seq int, coins types.Coins) basecoin.Tx {
|
||||
addrIn := at.accIn.Account.PubKey.Address()
|
||||
addrOut := at.accOut.Account.PubKey.Address()
|
||||
|
||||
in := []coin.TxInput{{Address: stack.SigPerm(addrIn), Coins: coins, Sequence: seq}}
|
||||
out := []coin.TxOutput{{Address: stack.SigPerm(addrOut), Coins: coins}}
|
||||
tx := coin.NewSendTx(in, out)
|
||||
tx = txs.NewChain(at.chainID, tx)
|
||||
stx := txs.NewMulti(tx)
|
||||
txs.Sign(stx, at.accIn.PrivKey)
|
||||
return stx.Wrap()
|
||||
}
|
||||
|
||||
// set the account on the app through SetOption
|
||||
|
@ -69,45 +81,51 @@ func (at *appTest) reset() {
|
|||
require.True(at.t, resabci.IsOK(), resabci)
|
||||
}
|
||||
|
||||
func getBalance(pk crypto.PubKey, state types.KVStore) (types.Coins, error) {
|
||||
return getAddr(pk.Address(), state)
|
||||
}
|
||||
|
||||
func getAddr(addr []byte, state types.KVStore) (types.Coins, error) {
|
||||
actor := stack.SigPerm(addr)
|
||||
acct, err := coin.NewAccountant("").GetAccount(state, actor)
|
||||
return acct.Coins, err
|
||||
}
|
||||
|
||||
// returns the final balance and expected balance for input and output accounts
|
||||
func (at *appTest) exec(tx *types.SendTx, checkTx bool) (res abci.Result, inputGot, inputExp, outputGot, outputExpected types.Coins) {
|
||||
func (at *appTest) exec(t *testing.T, tx basecoin.Tx, checkTx bool) (res abci.Result, diffIn, diffOut types.Coins) {
|
||||
require := require.New(t)
|
||||
|
||||
initBalIn := at.app.GetState().GetAccount(at.accIn.Account.PubKey.Address()).Balance
|
||||
initBalOut := at.app.GetState().GetAccount(at.accOut.Account.PubKey.Address()).Balance
|
||||
initBalIn, err := getBalance(at.accIn.Account.PubKey, at.app.GetState())
|
||||
require.Nil(err, "%+v", err)
|
||||
initBalOut, err := getBalance(at.accOut.Account.PubKey, at.app.GetState())
|
||||
require.Nil(err, "%+v", err)
|
||||
|
||||
txBytes := []byte(wire.BinaryBytes(struct{ types.Tx }{tx}))
|
||||
txBytes := wire.BinaryBytes(tx)
|
||||
if checkTx {
|
||||
res = at.app.CheckTx(txBytes)
|
||||
} else {
|
||||
res = at.app.DeliverTx(txBytes)
|
||||
}
|
||||
|
||||
endBalIn := at.app.GetState().GetAccount(at.accIn.Account.PubKey.Address()).Balance
|
||||
endBalOut := at.app.GetState().GetAccount(at.accOut.Account.PubKey.Address()).Balance
|
||||
decrBalInExp := tx.Outputs[0].Coins.Plus(types.Coins{tx.Fee})
|
||||
return res, endBalIn, initBalIn.Minus(decrBalInExp), endBalOut, initBalOut.Plus(tx.Outputs[0].Coins)
|
||||
endBalIn, err := getBalance(at.accIn.Account.PubKey, at.app.GetState())
|
||||
require.Nil(err, "%+v", err)
|
||||
endBalOut, err := getBalance(at.accOut.Account.PubKey, at.app.GetState())
|
||||
require.Nil(err, "%+v", err)
|
||||
return res, endBalIn.Minus(initBalIn), endBalOut.Minus(initBalOut)
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
|
||||
func TestSplitKey(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
prefix, suffix := splitKey("foo/bar")
|
||||
assert.EqualValues("foo", prefix)
|
||||
assert.EqualValues("bar", suffix)
|
||||
|
||||
prefix, suffix = splitKey("foobar")
|
||||
assert.EqualValues("foobar", prefix)
|
||||
assert.EqualValues("", suffix)
|
||||
}
|
||||
|
||||
func TestSetOption(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
eyesCli := eyes.NewLocalClient("", 0)
|
||||
app := NewBasecoin(DefaultHandler(), eyesCli,
|
||||
log.TestingLogger().With("module", "app"))
|
||||
app := NewBasecoin(
|
||||
DefaultHandler(),
|
||||
eyesCli,
|
||||
log.TestingLogger().With("module", "app"),
|
||||
)
|
||||
|
||||
//testing ChainID
|
||||
chainID := "testChain"
|
||||
|
@ -116,15 +134,16 @@ func TestSetOption(t *testing.T) {
|
|||
assert.EqualValues(res, "Success")
|
||||
|
||||
// make a nice account...
|
||||
accIn := types.MakeAcc("input0")
|
||||
accsInBytes, err := json.Marshal(accIn.Account)
|
||||
accIn := types.MakeAcc("input0").Account
|
||||
accsInBytes, err := json.Marshal(accIn)
|
||||
assert.Nil(err)
|
||||
res = app.SetOption("base/account", string(accsInBytes))
|
||||
require.EqualValues(res, "Success")
|
||||
|
||||
// make sure it is set correctly, with some balance
|
||||
acct := types.GetAccount(app.GetState(), accIn.PubKey.Address())
|
||||
require.NotNil(acct)
|
||||
assert.Equal(accIn.Balance, acct.Balance)
|
||||
coins, err := getBalance(accIn.PubKey, app.state)
|
||||
require.Nil(err)
|
||||
assert.Equal(accIn.Balance, coins)
|
||||
|
||||
// let's parse an account with badly sorted coins...
|
||||
unsortAddr, err := hex.DecodeString("C471FB670E44D219EE6DF2FC284BE38793ACBCE1")
|
||||
|
@ -148,10 +167,11 @@ func TestSetOption(t *testing.T) {
|
|||
}`
|
||||
res = app.SetOption("base/account", unsortAcc)
|
||||
require.EqualValues(res, "Success")
|
||||
acct = types.GetAccount(app.GetState(), unsortAddr)
|
||||
require.NotNil(acct)
|
||||
assert.True(acct.Balance.IsValid())
|
||||
assert.Equal(unsortCoins, acct.Balance)
|
||||
|
||||
coins, err = getAddr(unsortAddr, app.state)
|
||||
require.Nil(err)
|
||||
assert.True(coins.IsValid())
|
||||
assert.Equal(unsortCoins, coins)
|
||||
|
||||
res = app.SetOption("base/dslfkgjdas", "")
|
||||
assert.NotEqual(res, "Success")
|
||||
|
@ -172,33 +192,32 @@ func TestTx(t *testing.T) {
|
|||
//Bad Balance
|
||||
at.accIn.Balance = types.Coins{{"mycoin", 2}}
|
||||
at.acc2app(at.accIn.Account)
|
||||
res, _, _, _, _ := at.exec(at.getTx(1), true)
|
||||
res, _, _ := at.exec(t, at.getTx(1, types.Coins{{"mycoin", 5}}), true)
|
||||
assert.True(res.IsErr(), "ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res)
|
||||
res, inGot, inExp, outGot, outExp := at.exec(at.getTx(1), false)
|
||||
res, diffIn, diffOut := at.exec(t, at.getTx(1, types.Coins{{"mycoin", 5}}), false)
|
||||
assert.True(res.IsErr(), "ExecTx/Bad DeliverTx: Expected error return from ExecTx, returned: %v", res)
|
||||
assert.False(inGot.IsEqual(inExp), "ExecTx/Bad DeliverTx: shouldn't be equal, inGot: %v, inExp: %v", inGot, inExp)
|
||||
assert.False(outGot.IsEqual(outExp), "ExecTx/Bad DeliverTx: shouldn't be equal, outGot: %v, outExp: %v", outGot, outExp)
|
||||
assert.True(diffIn.IsZero())
|
||||
assert.True(diffOut.IsZero())
|
||||
|
||||
//Regular CheckTx
|
||||
at.reset()
|
||||
res, _, _, _, _ = at.exec(at.getTx(1), true)
|
||||
res, _, _ = at.exec(t, at.getTx(1, types.Coins{{"mycoin", 5}}), true)
|
||||
assert.True(res.IsOK(), "ExecTx/Good CheckTx: Expected OK return from ExecTx, Error: %v", res)
|
||||
|
||||
//Regular DeliverTx
|
||||
at.reset()
|
||||
res, inGot, inExp, outGot, outExp = at.exec(at.getTx(1), false)
|
||||
amt := types.Coins{{"mycoin", 3}}
|
||||
res, diffIn, diffOut = at.exec(t, at.getTx(1, amt), false)
|
||||
assert.True(res.IsOK(), "ExecTx/Good DeliverTx: Expected OK return from ExecTx, Error: %v", res)
|
||||
assert.True(inGot.IsEqual(inExp),
|
||||
"ExecTx/good DeliverTx: unexpected change in input coins, inGot: %v, inExp: %v", inGot, inExp)
|
||||
assert.True(outGot.IsEqual(outExp),
|
||||
"ExecTx/good DeliverTx: unexpected change in output coins, outGot: %v, outExp: %v", outGot, outExp)
|
||||
assert.Equal(amt.Negative(), diffIn)
|
||||
assert.Equal(amt, diffOut)
|
||||
}
|
||||
|
||||
func TestQuery(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
at := newAppTest(t)
|
||||
|
||||
res, _, _, _, _ := at.exec(at.getTx(1), false)
|
||||
res, _, _ := at.exec(t, at.getTx(1, types.Coins{{"mycoin", 5}}), false)
|
||||
assert.True(res.IsOK(), "Commit, DeliverTx: Expected OK return from DeliverTx, Error: %v", res)
|
||||
|
||||
resQueryPreCommit := at.app.Query(abci.RequestQuery{
|
||||
|
|
|
@ -15,7 +15,6 @@ type Handler interface {
|
|||
SetOptioner
|
||||
Named
|
||||
// TODO: flesh these out as well
|
||||
// SetOption(store types.KVStore, key, value string) (log string)
|
||||
// InitChain(store types.KVStore, vals []*abci.Validator)
|
||||
// BeginBlock(store types.KVStore, hash []byte, header *abci.Header)
|
||||
// EndBlock(store types.KVStore, height uint64) abci.ResponseEndBlock
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
"github.com/tendermint/basecoin/stack"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
|
||||
|
@ -24,7 +25,7 @@ var _ basecoin.Handler = Handler{}
|
|||
|
||||
func NewHandler() Handler {
|
||||
return Handler{
|
||||
Accountant: Accountant{Prefix: []byte(NameCoin + "/")},
|
||||
Accountant: NewAccountant(""),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +42,7 @@ func (h Handler) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.
|
|||
|
||||
// now make sure there is money
|
||||
for _, in := range send.Inputs {
|
||||
_, err = h.CheckCoins(store, in.Address, in.Coins, in.Sequence)
|
||||
_, err = h.CheckCoins(store, in.Address, in.Coins.Negative(), in.Sequence)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
@ -91,8 +92,9 @@ func (h Handler) SetOption(l log.Logger, store types.KVStore, key, value string)
|
|||
if err != nil {
|
||||
return "", ErrInvalidAddress()
|
||||
}
|
||||
actor := basecoin.Actor{App: NameCoin, Address: addr}
|
||||
err = storeAccount(store, h.makeKey(actor), acc.ToAccount())
|
||||
// this sets the permission for a public key signature, use that app
|
||||
actor := stack.SigPerm(addr)
|
||||
err = storeAccount(store, h.MakeKey(actor), acc.ToAccount())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ func TestDeliverTx(t *testing.T) {
|
|||
store := types.NewMemKVStore()
|
||||
for _, m := range tc.init {
|
||||
acct := Account{Coins: m.coins}
|
||||
err := storeAccount(store, h.makeKey(m.addr), acct)
|
||||
err := storeAccount(store, h.MakeKey(m.addr), acct)
|
||||
require.Nil(err, "%d: %+v", i, err)
|
||||
}
|
||||
|
||||
|
@ -153,7 +153,7 @@ func TestDeliverTx(t *testing.T) {
|
|||
assert.Nil(err, "%d: %+v", i, err)
|
||||
// make sure the final balances are correct
|
||||
for _, f := range tc.final {
|
||||
acct, err := loadAccount(store, h.makeKey(f.addr))
|
||||
acct, err := loadAccount(store, h.MakeKey(f.addr))
|
||||
assert.Nil(err, "%d: %+v", i, err)
|
||||
assert.Equal(f.coins, acct.Coins)
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ func TestSetOption(t *testing.T) {
|
|||
|
||||
// check state is proper
|
||||
for _, f := range tc.expected {
|
||||
acct, err := loadAccount(store, h.makeKey(f.addr))
|
||||
acct, err := loadAccount(store, h.MakeKey(f.addr))
|
||||
assert.Nil(err, "%d: %+v", i, err)
|
||||
assert.Equal(f.coins, acct.Coins)
|
||||
}
|
||||
|
|
|
@ -14,8 +14,17 @@ type Accountant struct {
|
|||
Prefix []byte
|
||||
}
|
||||
|
||||
func NewAccountant(prefix string) Accountant {
|
||||
if prefix == "" {
|
||||
prefix = NameCoin
|
||||
}
|
||||
return Accountant{
|
||||
Prefix: []byte(prefix + "/"),
|
||||
}
|
||||
}
|
||||
|
||||
func (a Accountant) GetAccount(store types.KVStore, addr basecoin.Actor) (Account, error) {
|
||||
acct, err := loadAccount(store, a.makeKey(addr))
|
||||
acct, err := loadAccount(store, a.MakeKey(addr))
|
||||
// for empty accounts, don't return an error, but rather an empty account
|
||||
if IsNoAccountErr(err) {
|
||||
err = nil
|
||||
|
@ -36,7 +45,7 @@ func (a Accountant) ChangeCoins(store types.KVStore, addr basecoin.Actor, coins
|
|||
return acct.Coins, err
|
||||
}
|
||||
|
||||
err = storeAccount(store, a.makeKey(addr), acct)
|
||||
err = storeAccount(store, a.MakeKey(addr), acct)
|
||||
return acct.Coins, err
|
||||
}
|
||||
|
||||
|
@ -44,7 +53,7 @@ func (a Accountant) ChangeCoins(store types.KVStore, addr basecoin.Actor, coins
|
|||
//
|
||||
// it doesn't save anything, that is up to you to decide (Check/Change Coins)
|
||||
func (a Accountant) updateCoins(store types.KVStore, addr basecoin.Actor, coins types.Coins, seq int) (acct Account, err error) {
|
||||
acct, err = loadAccount(store, a.makeKey(addr))
|
||||
acct, err = loadAccount(store, a.MakeKey(addr))
|
||||
// we can increase an empty account...
|
||||
if IsNoAccountErr(err) && coins.IsPositive() {
|
||||
err = nil
|
||||
|
@ -71,7 +80,7 @@ func (a Accountant) updateCoins(store types.KVStore, addr basecoin.Actor, coins
|
|||
return acct, nil
|
||||
}
|
||||
|
||||
func (a Accountant) makeKey(addr basecoin.Actor) []byte {
|
||||
func (a Accountant) MakeKey(addr basecoin.Actor) []byte {
|
||||
key := addr.Bytes()
|
||||
if len(a.Prefix) > 0 {
|
||||
key = append(a.Prefix, key...)
|
||||
|
|
Loading…
Reference in New Issue