Move ChainID into context

This commit is contained in:
Ethan Frey 2017-07-03 17:32:01 +02:00
parent ef0ab758ed
commit 159574db89
16 changed files with 170 additions and 124 deletions

View File

@ -1,23 +1,22 @@
package app package app
import ( import (
"encoding/hex"
"encoding/json"
"strings" "strings"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
wire "github.com/tendermint/go-wire" "github.com/tendermint/basecoin"
eyes "github.com/tendermint/merkleeyes/client" eyes "github.com/tendermint/merkleeyes/client"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
"github.com/tendermint/basecoin/errors"
"github.com/tendermint/basecoin/modules/coin"
"github.com/tendermint/basecoin/stack"
sm "github.com/tendermint/basecoin/state" sm "github.com/tendermint/basecoin/state"
"github.com/tendermint/basecoin/types"
"github.com/tendermint/basecoin/version" "github.com/tendermint/basecoin/version"
) )
const ( const (
maxTxSize = 10240
PluginNameBase = "base" PluginNameBase = "base"
) )
@ -25,23 +24,29 @@ type Basecoin struct {
eyesCli *eyes.Client eyesCli *eyes.Client
state *sm.State state *sm.State
cacheState *sm.State cacheState *sm.State
plugins *types.Plugins handler basecoin.Handler
logger log.Logger logger log.Logger
} }
func NewBasecoin(eyesCli *eyes.Client, l log.Logger) *Basecoin { func NewBasecoin(h basecoin.Handler, eyesCli *eyes.Client, l log.Logger) *Basecoin {
state := sm.NewState(eyesCli, l.With("module", "state")) state := sm.NewState(eyesCli, l.With("module", "state"))
plugins := types.NewPlugins()
return &Basecoin{ return &Basecoin{
handler: h,
eyesCli: eyesCli, eyesCli: eyesCli,
state: state, state: state,
cacheState: nil, cacheState: nil,
plugins: plugins,
logger: l, logger: l,
} }
} }
// placeholder to just handle sendtx
func DefaultHandler() basecoin.Handler {
// use the default stack
h := coin.NewHandler()
return stack.NewDefault().Use(h)
}
// XXX For testing, not thread safe! // XXX For testing, not thread safe!
func (app *Basecoin) GetState() *sm.State { func (app *Basecoin) GetState() *sm.State {
return app.state.CacheWrap() return app.state.CacheWrap()
@ -60,87 +65,85 @@ func (app *Basecoin) Info() abci.ResponseInfo {
} }
} }
func (app *Basecoin) RegisterPlugin(plugin types.Plugin) {
app.plugins.RegisterPlugin(plugin)
}
// ABCI::SetOption // ABCI::SetOption
func (app *Basecoin) SetOption(key string, value string) string { func (app *Basecoin) SetOption(key string, value string) string {
pluginName, key := splitKey(key) // TODO
if pluginName != PluginNameBase { return "todo"
// Set option on plugin // pluginName, key := splitKey(key)
plugin := app.plugins.GetByName(pluginName) // if pluginName != PluginNameBase {
if plugin == nil { // // Set option on plugin
return "Invalid plugin name: " + pluginName // plugin := app.plugins.GetByName(pluginName)
} // if plugin == nil {
app.logger.Info("SetOption on plugin", "plugin", pluginName, "key", key, "value", value) // return "Invalid plugin name: " + pluginName
return plugin.SetOption(app.state, key, value) // }
} else { // app.logger.Info("SetOption on plugin", "plugin", pluginName, "key", key, "value", value)
// Set option on basecoin // return plugin.SetOption(app.state, key, value)
switch key { // } else {
case "chain_id": // // Set option on basecoin
app.state.SetChainID(value) // switch key {
return "Success" // case "chain_id":
case "account": // app.state.SetChainID(value)
var acc GenesisAccount // return "Success"
err := json.Unmarshal([]byte(value), &acc) // case "account":
if err != nil { // var acc GenesisAccount
return "Error decoding acc message: " + err.Error() // err := json.Unmarshal([]byte(value), &acc)
} // if err != nil {
acc.Balance.Sort() // return "Error decoding acc message: " + err.Error()
addr, err := acc.GetAddr() // }
if err != nil { // acc.Balance.Sort()
return "Invalid address: " + err.Error() // addr, err := acc.GetAddr()
} // if err != nil {
app.state.SetAccount(addr, acc.ToAccount()) // return "Invalid address: " + err.Error()
app.logger.Info("SetAccount", "addr", hex.EncodeToString(addr), "acc", acc) // }
// app.state.SetAccount(addr, acc.ToAccount())
// app.logger.Info("SetAccount", "addr", hex.EncodeToString(addr), "acc", acc)
return "Success" // return "Success"
} // }
return "Unrecognized option key " + key // return "Unrecognized option key " + key
} // }
} }
// ABCI::DeliverTx // ABCI::DeliverTx
func (app *Basecoin) DeliverTx(txBytes []byte) (res abci.Result) { func (app *Basecoin) DeliverTx(txBytes []byte) abci.Result {
if len(txBytes) > maxTxSize { tx, err := basecoin.LoadTx(txBytes)
return abci.ErrBaseEncodingError.AppendLog("Tx size exceeds maximum")
}
// Decode tx
var tx types.Tx
err := wire.ReadBinaryBytes(txBytes, &tx)
if err != nil { if err != nil {
return abci.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error()) return errors.Result(err)
} }
// Validate and exec tx // TODO: can we abstract this setup and commit logic??
res = sm.ExecTx(app.state, app.plugins, tx, false, nil) cache := app.state.CacheWrap()
if res.IsErr() { ctx := stack.NewContext(app.state.GetChainID(),
return res.PrependLog("Error in DeliverTx") app.logger.With("call", "delivertx"))
res, err := app.handler.DeliverTx(ctx, cache, tx)
if err != nil {
// discard the cache...
return errors.Result(err)
} }
return res // commit the cache and return result
cache.CacheSync()
return res.ToABCI()
} }
// ABCI::CheckTx // ABCI::CheckTx
func (app *Basecoin) CheckTx(txBytes []byte) (res abci.Result) { func (app *Basecoin) CheckTx(txBytes []byte) abci.Result {
if len(txBytes) > maxTxSize { tx, err := basecoin.LoadTx(txBytes)
return abci.ErrBaseEncodingError.AppendLog("Tx size exceeds maximum")
}
// Decode tx
var tx types.Tx
err := wire.ReadBinaryBytes(txBytes, &tx)
if err != nil { if err != nil {
return abci.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error()) return errors.Result(err)
} }
// Validate tx // TODO: can we abstract this setup and commit logic??
res = sm.ExecTx(app.cacheState, app.plugins, tx, true, nil) ctx := stack.NewContext(app.state.GetChainID(),
if res.IsErr() { app.logger.With("call", "checktx"))
return res.PrependLog("Error in 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)
if err != nil {
return errors.Result(err)
} }
return abci.OK return res.ToABCI()
} }
// ABCI::Query // ABCI::Query
@ -151,12 +154,6 @@ func (app *Basecoin) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQu
return return
} }
// handle special path for account info
if reqQuery.Path == "/account" {
reqQuery.Path = "/key"
reqQuery.Data = types.AccountKey(reqQuery.Data)
}
resQuery, err := app.eyesCli.QuerySync(reqQuery) resQuery, err := app.eyesCli.QuerySync(reqQuery)
if err != nil { if err != nil {
resQuery.Log = "Failed to query MerkleEyes: " + err.Error() resQuery.Log = "Failed to query MerkleEyes: " + err.Error()
@ -183,24 +180,24 @@ func (app *Basecoin) Commit() (res abci.Result) {
// ABCI::InitChain // ABCI::InitChain
func (app *Basecoin) InitChain(validators []*abci.Validator) { func (app *Basecoin) InitChain(validators []*abci.Validator) {
for _, plugin := range app.plugins.GetList() { // for _, plugin := range app.plugins.GetList() {
plugin.InitChain(app.state, validators) // plugin.InitChain(app.state, validators)
} // }
} }
// ABCI::BeginBlock // ABCI::BeginBlock
func (app *Basecoin) BeginBlock(hash []byte, header *abci.Header) { func (app *Basecoin) BeginBlock(hash []byte, header *abci.Header) {
for _, plugin := range app.plugins.GetList() { // for _, plugin := range app.plugins.GetList() {
plugin.BeginBlock(app.state, hash, header) // plugin.BeginBlock(app.state, hash, header)
} // }
} }
// ABCI::EndBlock // ABCI::EndBlock
func (app *Basecoin) EndBlock(height uint64) (res abci.ResponseEndBlock) { func (app *Basecoin) EndBlock(height uint64) (res abci.ResponseEndBlock) {
for _, plugin := range app.plugins.GetList() { // for _, plugin := range app.plugins.GetList() {
pluginRes := plugin.EndBlock(app.state, height) // pluginRes := plugin.EndBlock(app.state, height)
res.Diffs = append(res.Diffs, pluginRes.Diffs...) // res.Diffs = append(res.Diffs, pluginRes.Diffs...)
} // }
return return
} }

View File

@ -56,7 +56,8 @@ func (at *appTest) reset() {
at.accOut = types.MakeAcc("output0") at.accOut = types.MakeAcc("output0")
eyesCli := eyes.NewLocalClient("", 0) eyesCli := eyes.NewLocalClient("", 0)
at.app = NewBasecoin(eyesCli, log.TestingLogger().With("module", "app")) at.app = NewBasecoin(DefaultHandler(), eyesCli,
log.TestingLogger().With("module", "app"))
res := at.app.SetOption("base/chain_id", at.chainID) res := at.app.SetOption("base/chain_id", at.chainID)
require.EqualValues(at.t, res, "Success") require.EqualValues(at.t, res, "Success")
@ -105,7 +106,8 @@ func TestSetOption(t *testing.T) {
require := require.New(t) require := require.New(t)
eyesCli := eyes.NewLocalClient("", 0) eyesCli := eyes.NewLocalClient("", 0)
app := NewBasecoin(eyesCli, log.TestingLogger().With("module", "app")) app := NewBasecoin(DefaultHandler(), eyesCli,
log.TestingLogger().With("module", "app"))
//testing ChainID //testing ChainID
chainID := "testChain" chainID := "testChain"

View File

@ -19,7 +19,7 @@ const genesisAcctFilepath = "./testdata/genesis2.json"
func TestLoadGenesisDoNotFailIfAppOptionsAreMissing(t *testing.T) { func TestLoadGenesisDoNotFailIfAppOptionsAreMissing(t *testing.T) {
eyesCli := eyescli.NewLocalClient("", 0) eyesCli := eyescli.NewLocalClient("", 0)
app := NewBasecoin(eyesCli, log.TestingLogger()) app := NewBasecoin(DefaultHandler(), eyesCli, log.TestingLogger())
err := app.LoadGenesis("./testdata/genesis3.json") err := app.LoadGenesis("./testdata/genesis3.json")
require.Nil(t, err, "%+v", err) require.Nil(t, err, "%+v", err)
} }
@ -28,7 +28,7 @@ func TestLoadGenesis(t *testing.T) {
assert, require := assert.New(t), require.New(t) assert, require := assert.New(t), require.New(t)
eyesCli := eyescli.NewLocalClient("", 0) eyesCli := eyescli.NewLocalClient("", 0)
app := NewBasecoin(eyesCli, log.TestingLogger()) app := NewBasecoin(DefaultHandler(), eyesCli, log.TestingLogger())
err := app.LoadGenesis(genesisFilepath) err := app.LoadGenesis(genesisFilepath)
require.Nil(err, "%+v", err) require.Nil(err, "%+v", err)
@ -65,7 +65,7 @@ func TestLoadGenesisAccountAddress(t *testing.T) {
assert, require := assert.New(t), require.New(t) assert, require := assert.New(t), require.New(t)
eyesCli := eyescli.NewLocalClient("", 0) eyesCli := eyescli.NewLocalClient("", 0)
app := NewBasecoin(eyesCli, log.TestingLogger()) app := NewBasecoin(DefaultHandler(), eyesCli, log.TestingLogger())
err := app.LoadGenesis(genesisAcctFilepath) err := app.LoadGenesis(genesisAcctFilepath)
require.Nil(err, "%+v", err) require.Nil(err, "%+v", err)

View File

@ -10,6 +10,7 @@ import (
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/tendermint/abci/server" "github.com/tendermint/abci/server"
"github.com/tendermint/basecoin"
eyesApp "github.com/tendermint/merkleeyes/app" eyesApp "github.com/tendermint/merkleeyes/app"
eyes "github.com/tendermint/merkleeyes/client" eyes "github.com/tendermint/merkleeyes/client"
"github.com/tendermint/tmlibs/cli" "github.com/tendermint/tmlibs/cli"
@ -21,6 +22,8 @@ import (
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
"github.com/tendermint/basecoin/app" "github.com/tendermint/basecoin/app"
"github.com/tendermint/basecoin/modules/coin"
"github.com/tendermint/basecoin/stack"
) )
var StartCmd = &cobra.Command{ var StartCmd = &cobra.Command{
@ -48,6 +51,22 @@ func init() {
tcmd.AddNodeFlags(StartCmd) tcmd.AddNodeFlags(StartCmd)
} }
// TODO: setup handler instead of Plugins
func getHandler() basecoin.Handler {
// use the default stack
h := coin.NewHandler()
app := stack.NewDefault("change-this").Use(h)
return app
// register IBC plugn
// basecoinApp.RegisterPlugin(NewIBCPlugin())
// register all other plugins
// for _, p := range plugins {
// basecoinApp.RegisterPlugin(p.newPlugin())
// }
}
func startCmd(cmd *cobra.Command, args []string) error { func startCmd(cmd *cobra.Command, args []string) error {
rootDir := viper.GetString(cli.HomeFlag) rootDir := viper.GetString(cli.HomeFlag)
meyes := viper.GetString(FlagEyes) meyes := viper.GetString(FlagEyes)
@ -66,15 +85,8 @@ func startCmd(cmd *cobra.Command, args []string) error {
} }
// Create Basecoin app // Create Basecoin app
basecoinApp := app.NewBasecoin(eyesCli, logger.With("module", "app")) h := app.DefaultHandler()
basecoinApp := app.NewBasecoin(h, eyesCli, logger.With("module", "app"))
// register IBC plugn
// basecoinApp.RegisterPlugin(NewIBCPlugin())
// register all other plugins
for _, p := range plugins {
basecoinApp.RegisterPlugin(p.newPlugin())
}
// if chain_id has not been set yet, load the genesis. // if chain_id has not been set yet, load the genesis.
// else, assume it's been loaded // else, assume it's been loaded

View File

@ -34,4 +34,5 @@ type Context interface {
HasPermission(perm Actor) bool HasPermission(perm Actor) bool
IsParent(ctx Context) bool IsParent(ctx Context) bool
Reset() Context Reset() Context
ChainID() string
} }

View File

@ -68,7 +68,7 @@ func TestHandlerValidation(t *testing.T) {
} }
for i, tc := range cases { for i, tc := range cases {
ctx := stack.MockContext().WithPermissions(tc.perms...) ctx := stack.MockContext("base-chain").WithPermissions(tc.perms...)
_, err := checkTx(ctx, tc.tx) _, err := checkTx(ctx, tc.tx)
if tc.valid { if tc.valid {
assert.Nil(err, "%d: %+v", i, err) assert.Nil(err, "%d: %+v", i, err)
@ -142,7 +142,7 @@ func TestDeliverTx(t *testing.T) {
require.Nil(err, "%d: %+v", i, err) require.Nil(err, "%d: %+v", i, err)
} }
ctx := stack.MockContext().WithPermissions(tc.perms...) ctx := stack.MockContext("base-chain").WithPermissions(tc.perms...)
_, err := h.DeliverTx(ctx, store, tc.tx) _, err := h.DeliverTx(ctx, store, tc.tx)
if len(tc.final) > 0 { // valid if len(tc.final) > 0 { // valid
assert.Nil(err, "%d: %+v", i, err) assert.Nil(err, "%d: %+v", i, err)

View File

@ -12,9 +12,7 @@ const (
) )
// Chain enforces that this tx was bound to the named chain // Chain enforces that this tx was bound to the named chain
type Chain struct { type Chain struct{}
ChainID string
}
func (_ Chain) Name() string { func (_ Chain) Name() string {
return NameRecovery return NameRecovery
@ -23,7 +21,7 @@ func (_ Chain) Name() string {
var _ Middleware = Chain{} var _ Middleware = Chain{}
func (c Chain) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) { func (c Chain) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) {
stx, err := c.checkChain(tx) stx, err := c.checkChain(ctx.ChainID(), tx)
if err != nil { if err != nil {
return res, err return res, err
} }
@ -31,7 +29,7 @@ func (c Chain) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx
} }
func (c Chain) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) { func (c Chain) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) {
stx, err := c.checkChain(tx) stx, err := c.checkChain(ctx.ChainID(), tx)
if err != nil { if err != nil {
return res, err return res, err
} }
@ -39,12 +37,12 @@ func (c Chain) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.
} }
// checkChain makes sure the tx is a txs.Chain and // checkChain makes sure the tx is a txs.Chain and
func (c Chain) checkChain(tx basecoin.Tx) (basecoin.Tx, error) { func (c Chain) checkChain(chainID string, tx basecoin.Tx) (basecoin.Tx, error) {
ctx, ok := tx.Unwrap().(*txs.Chain) ctx, ok := tx.Unwrap().(*txs.Chain)
if !ok { if !ok {
return tx, errors.ErrNoChain() return tx, errors.ErrNoChain()
} }
if ctx.ChainID != c.ChainID { if ctx.ChainID != chainID {
return tx, errors.ErrWrongChain(ctx.ChainID) return tx, errors.ErrWrongChain(ctx.ChainID)
} }
return ctx.Tx, nil return ctx.Tx, nil

View File

@ -30,12 +30,12 @@ func TestChain(t *testing.T) {
} }
// generic args here... // generic args here...
ctx := NewContext(log.NewNopLogger()) ctx := NewContext(chainID, log.NewNopLogger())
store := types.NewMemKVStore() store := types.NewMemKVStore()
// build the stack // build the stack
ok := OKHandler{msg} ok := OKHandler{msg}
app := New(Chain{chainID}).Use(ok) app := New(Chain{}).Use(ok)
for idx, tc := range cases { for idx, tc := range cases {
i := strconv.Itoa(idx) i := strconv.Itoa(idx)

View File

@ -17,20 +17,26 @@ type nonce int64
type secureContext struct { type secureContext struct {
id nonce id nonce
chain string
app string app string
perms []basecoin.Actor perms []basecoin.Actor
log.Logger log.Logger
} }
func NewContext(logger log.Logger) basecoin.Context { func NewContext(chain string, logger log.Logger) basecoin.Context {
return secureContext{ return secureContext{
id: nonce(rand.Int63()), id: nonce(rand.Int63()),
chain: chain,
Logger: logger, Logger: logger,
} }
} }
var _ basecoin.Context = secureContext{} var _ basecoin.Context = secureContext{}
func (c secureContext) ChainID() string {
return c.chain
}
// WithPermissions will panic if they try to set permission without the proper app // WithPermissions will panic if they try to set permission without the proper app
func (c secureContext) WithPermissions(perms ...basecoin.Actor) basecoin.Context { func (c secureContext) WithPermissions(perms ...basecoin.Actor) basecoin.Context {
// the guard makes sure you only set permissions for the app you are inside // the guard makes sure you only set permissions for the app you are inside
@ -44,6 +50,7 @@ func (c secureContext) WithPermissions(perms ...basecoin.Actor) basecoin.Context
return secureContext{ return secureContext{
id: c.id, id: c.id,
chain: c.chain,
app: c.app, app: c.app,
perms: append(c.perms, perms...), perms: append(c.perms, perms...),
Logger: c.Logger, Logger: c.Logger,
@ -73,6 +80,7 @@ func (c secureContext) IsParent(other basecoin.Context) bool {
func (c secureContext) Reset() basecoin.Context { func (c secureContext) Reset() basecoin.Context {
return secureContext{ return secureContext{
id: c.id, id: c.id,
chain: c.chain,
app: c.app, app: c.app,
perms: nil, perms: nil,
Logger: c.Logger, Logger: c.Logger,
@ -88,6 +96,7 @@ func withApp(ctx basecoin.Context, app string) basecoin.Context {
} }
return secureContext{ return secureContext{
id: sc.id, id: sc.id,
chain: sc.chain,
app: app, app: app,
perms: sc.perms, perms: sc.perms,
Logger: sc.Logger, Logger: sc.Logger,

View File

@ -15,7 +15,7 @@ import (
func TestOK(t *testing.T) { func TestOK(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
ctx := NewContext(log.NewNopLogger()) ctx := NewContext("test-chain", log.NewNopLogger())
store := types.NewMemKVStore() store := types.NewMemKVStore()
data := "this looks okay" data := "this looks okay"
tx := basecoin.Tx{} tx := basecoin.Tx{}
@ -33,7 +33,7 @@ func TestOK(t *testing.T) {
func TestFail(t *testing.T) { func TestFail(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
ctx := NewContext(log.NewNopLogger()) ctx := NewContext("test-chain", log.NewNopLogger())
store := types.NewMemKVStore() store := types.NewMemKVStore()
msg := "big problem" msg := "big problem"
tx := basecoin.Tx{} tx := basecoin.Tx{}
@ -53,7 +53,7 @@ func TestFail(t *testing.T) {
func TestPanic(t *testing.T) { func TestPanic(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
ctx := NewContext(log.NewNopLogger()) ctx := NewContext("test-chain", log.NewNopLogger())
store := types.NewMemKVStore() store := types.NewMemKVStore()
msg := "system crash!" msg := "system crash!"
tx := basecoin.Tx{} tx := basecoin.Tx{}

View File

@ -57,12 +57,12 @@ func New(middlewares ...Middleware) *Stack {
// NewDefault sets up the common middlewares before your custom stack. // NewDefault sets up the common middlewares before your custom stack.
// //
// This is logger, recovery, signature, and chain // This is logger, recovery, signature, and chain
func NewDefault(chainID string, middlewares ...Middleware) *Stack { func NewDefault(middlewares ...Middleware) *Stack {
mids := []Middleware{ mids := []Middleware{
Logger{}, Logger{},
Recovery{}, Recovery{},
Signatures{}, Signatures{},
Chain{chainID}, Chain{},
} }
mids = append(mids, middlewares...) mids = append(mids, middlewares...)
return New(mids...) return New(mids...)

View File

@ -17,7 +17,7 @@ func TestPermissionSandbox(t *testing.T) {
require := require.New(t) require := require.New(t)
// generic args // generic args
ctx := NewContext(log.NewNopLogger()) ctx := NewContext("test-chain", log.NewNopLogger())
store := types.NewMemKVStore() store := types.NewMemKVStore()
raw := txs.NewRaw([]byte{1, 2, 3, 4}) raw := txs.NewRaw([]byte{1, 2, 3, 4})
rawBytes, err := data.ToWire(raw) rawBytes, err := data.ToWire(raw)

View File

@ -10,17 +10,23 @@ import (
type mockContext struct { type mockContext struct {
perms []basecoin.Actor perms []basecoin.Actor
chain string
log.Logger log.Logger
} }
func MockContext() basecoin.Context { func MockContext(chain string) basecoin.Context {
return mockContext{ return mockContext{
chain: chain,
Logger: log.NewNopLogger(), Logger: log.NewNopLogger(),
} }
} }
var _ basecoin.Context = mockContext{} var _ basecoin.Context = mockContext{}
func (c mockContext) ChainID() string {
return c.chain
}
// WithPermissions will panic if they try to set permission without the proper app // WithPermissions will panic if they try to set permission without the proper app
func (c mockContext) WithPermissions(perms ...basecoin.Actor) basecoin.Context { func (c mockContext) WithPermissions(perms ...basecoin.Actor) basecoin.Context {
return mockContext{ return mockContext{

View File

@ -15,7 +15,7 @@ func TestRecovery(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
// generic args here... // generic args here...
ctx := NewContext(log.NewNopLogger()) ctx := NewContext("test-chain", log.NewNopLogger())
store := types.NewMemKVStore() store := types.NewMemKVStore()
tx := basecoin.Tx{} tx := basecoin.Tx{}

View File

@ -17,7 +17,7 @@ func TestSignatureChecks(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
// generic args // generic args
ctx := NewContext(log.NewNopLogger()) ctx := NewContext("test-chain", log.NewNopLogger())
store := types.NewMemKVStore() store := types.NewMemKVStore()
raw := txs.NewRaw([]byte{1, 2, 3, 4}) raw := txs.NewRaw([]byte{1, 2, 3, 4})

21
tx.go
View File

@ -1,5 +1,12 @@
package basecoin package basecoin
import (
"github.com/pkg/errors"
"github.com/tendermint/go-wire/data"
)
const maxTxSize = 10240
// TxInner is the interface all concrete transactions should implement. // TxInner is the interface all concrete transactions should implement.
// //
// It adds bindings for clean un/marhsaling of the various implementations // It adds bindings for clean un/marhsaling of the various implementations
@ -15,6 +22,20 @@ type TxInner interface {
ValidateBasic() error ValidateBasic() error
} }
// LoadTx parses a tx from data
//
// TODO: label both errors with abci.CodeType_EncodingError
// need to move errors to avoid import cycle
func LoadTx(bin []byte) (tx Tx, err error) {
if len(bin) > maxTxSize {
return tx, errors.New("Tx size exceeds maximum")
}
// Decode tx
err = data.FromWire(bin, &tx)
return tx, err
}
// TODO: do we need this abstraction? TxLayer??? // TODO: do we need this abstraction? TxLayer???
// please review again after implementing "middleware" // please review again after implementing "middleware"