simplify baseapp and InitStater -> InitChainer

This commit is contained in:
Ethan Buchman 2018-02-16 20:15:38 -05:00
parent 96b734b729
commit c7df77ce3c
7 changed files with 51 additions and 232 deletions

View File

@ -1,9 +1,7 @@
package baseapp
import (
"bytes"
"fmt"
"os"
"runtime/debug"
"github.com/golang/protobuf/proto"
@ -27,7 +25,7 @@ type BaseApp struct {
db dbm.DB // common DB backend
cms sdk.CommitMultiStore // Main (uncached) state
txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx
InitStater sdk.InitStater // TODO unexpose
initChainer sdk.InitChainer //
anteHandler sdk.AnteHandler // ante handler for fee and auth
router Router // handle any kind of message
@ -43,34 +41,14 @@ type BaseApp struct {
var _ abci.Application = &BaseApp{}
// Create and name new BaseApp
func NewBaseApp(name string) *BaseApp {
var baseapp = &BaseApp{
logger: makeDefaultLogger(),
func NewBaseApp(name string, logger log.Logger, db dbm.DB) *BaseApp {
return &BaseApp{
logger: logger,
name: name,
db: nil,
cms: nil,
db: db,
cms: store.NewCommitMultiStore(db),
router: NewRouter(),
}
baseapp.initDB()
baseapp.initMultiStore()
return baseapp
}
// Create the underlying leveldb datastore which will
// persist the Merkle tree inner & leaf nodes.
func (app *BaseApp) initDB() {
db, err := dbm.NewGoLevelDB(app.name, "data")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
app.db = db
}
func (app *BaseApp) initMultiStore() {
cms := store.NewCommitMultiStore(app.db)
app.cms = cms
}
// BaseApp Name
@ -94,8 +72,8 @@ func (app *BaseApp) MountStore(key sdk.StoreKey, typ sdk.StoreType) {
func (app *BaseApp) SetTxDecoder(txDecoder sdk.TxDecoder) {
app.txDecoder = txDecoder
}
func (app *BaseApp) SetInitStater(initStater sdk.InitStater) {
app.InitStater = initStater
func (app *BaseApp) SetInitChainer(initChainer sdk.InitChainer) {
app.initChainer = initChainer
}
func (app *BaseApp) SetAnteHandler(ah sdk.AnteHandler) {
// deducts fee from payer, verifies signatures and nonces, sets Signers to ctx.
@ -170,6 +148,22 @@ func (app *BaseApp) initFromStore(mainKey sdk.StoreKey) error {
return nil
}
// NewContext returns a new Context suitable for AnteHandler (and indirectly Handler) processing.
// NOTE: txBytes may be nil to support TestApp.RunCheckTx
// and TestApp.RunDeliverTx.
func (app *BaseApp) NewContext(isCheckTx bool, txBytes []byte) sdk.Context {
store := app.getMultiStore(isCheckTx)
if store == nil {
panic("BaseApp.NewContext() requires BeginBlock(): missing store")
}
if app.header == nil {
panic("BaseApp.NewContext() requires BeginBlock(): missing header")
}
return sdk.NewContext(store, *app.header, isCheckTx, txBytes)
}
//----------------------------------------
// ABCI
@ -193,18 +187,18 @@ func (app *BaseApp) SetOption(req abci.RequestSetOption) (res abci.ResponseSetOp
// Implements ABCI
func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitChain) {
// TODO: Use req.Validators
// TODO: Use req.AppState in InitStater
if app.InitStater == nil {
if app.initChainer == nil {
// TODO: should we have some default handling of validators?
return
}
app.msDeliver = app.cms.CacheMultiStore()
ctx := app.GenesisContext(nil)
// get the store and make a context for the initialization
store := app.cms.CacheMultiStore()
ctx := sdk.NewContext(store, abci.Header{}, false, nil)
err := app.InitStater(ctx, nil)
err := app.initChainer(ctx, req)
if err != nil {
// TODO: something better https://github.com/cosmos/cosmos-sdk/issues/468
cmn.Exit(fmt.Sprintf("error initializing application genesis state: %v", err))
}
return
@ -376,20 +370,3 @@ func (app *BaseApp) getMultiStore(isCheckTx bool) sdk.MultiStore {
}
return app.msDeliver
}
// Return index of list with validator of same PubKey, or -1 if no match
func pubKeyIndex(val *abci.Validator, list []*abci.Validator) int {
for i, v := range list {
if bytes.Equal(val.PubKey, v.PubKey) {
return i
}
}
return -1
}
// Make a simple default logger
// TODO: Make log capturable for each transaction, and return it in
// ResponseDeliverTx.Log and ResponseCheckTx.Log.
func makeDefaultLogger() log.Logger {
return log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
}

View File

@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"os"
"testing"
"github.com/stretchr/testify/assert"
@ -12,12 +13,23 @@ import (
"github.com/tendermint/go-crypto"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func defaultLogger() log.Logger {
return log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
}
func newBaseApp(name string) *BaseApp {
logger := defaultLogger()
db := dbm.NewMemDB()
return NewBaseApp(name, logger, db)
}
func TestMountStores(t *testing.T) {
app := NewBaseApp(t.Name())
app := newBaseApp(t.Name())
// make some cap keys
capKey1 := sdk.NewKVStoreKey("key1")
@ -65,7 +77,7 @@ func (tx testUpdatePowerTx) GetSignatures() []sdk.StdSignature { return ni
func TestExecution(t *testing.T) {
// Create app.
app := NewBaseApp(t.Name())
app := newBaseApp(t.Name())
storeKeys := createMounts(app.cms)
app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) {
var ttx testUpdatePowerTx

View File

@ -1,36 +0,0 @@
package baseapp
import (
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/abci/types"
)
// NewContext returns a new Context suitable for AnteHandler (and indirectly Handler) processing.
// NOTE: txBytes may be nil to support TestApp.RunCheckTx
// and TestApp.RunDeliverTx.
func (app *BaseApp) NewContext(isCheckTx bool, txBytes []byte) sdk.Context {
var store sdk.MultiStore
if isCheckTx {
store = app.msCheck
} else {
store = app.msDeliver
}
if store == nil {
panic("BaseApp.NewContext() requires BeginBlock(): missing store")
}
if app.header == nil {
panic("BaseApp.NewContext() requires BeginBlock(): missing header")
}
return sdk.NewContext(store, *app.header, isCheckTx, txBytes)
}
// context used during genesis
func (app *BaseApp) GenesisContext(txBytes []byte) sdk.Context {
store := app.msDeliver
if store == nil {
panic("BaseApp.NewContext() requires BeginBlock(): missing store")
}
return sdk.NewContext(store, abci.Header{}, false, txBytes)
}

View File

@ -1,30 +0,0 @@
package baseapp
import (
"encoding/json"
"io/ioutil"
)
// TODO: remove from here and pass the AppState through InitChain
// GenesisDoc defines the initial conditions for a tendermint blockchain, in particular its validator set.
type GenesisDoc struct {
AppState json.RawMessage `json:"app_state,omitempty"`
}
// GenesisDocFromFile reads JSON data from a file and unmarshalls it into a GenesisDoc.
func LoadGenesisAppState(genesisPath string) (state json.RawMessage, err error) {
if genesisPath == "" {
return
}
jsonBlob, err := ioutil.ReadFile(genesisPath)
if err != nil {
return nil, err
}
genDoc := GenesisDoc{}
err = json.Unmarshal(jsonBlob, &genDoc)
if err != nil {
return nil, err
}
return genDoc.AppState, nil
}

View File

@ -1,104 +0,0 @@
package baseapp
import (
abci "github.com/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/baseapp/testtx"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// TestApp wraps BaseApp with helper methods,
// and exposes more functionality than otherwise needed.
type TestApp struct {
*BaseApp
// These get set as we receive them.
*abci.ResponseBeginBlock
*abci.ResponseEndBlock
}
func NewTestApp(bapp *BaseApp) *TestApp {
app := &TestApp{
BaseApp: bapp,
}
return app
}
// execute BaseApp BeginBlock
func (tapp *TestApp) RunBeginBlock() {
if tapp.header != nil {
panic("TestApp.header not nil, BeginBlock already run, or EndBlock not yet run.")
}
cms := tapp.CommitMultiStore()
lastCommit := cms.LastCommitID()
header := abci.Header{
ChainID: "chain_" + tapp.BaseApp.name,
Height: lastCommit.Version + 1,
Time: -1, // TODO
NumTxs: -1, // TODO
LastCommitHash: lastCommit.Hash,
DataHash: nil, // TODO
ValidatorsHash: nil, // TODO
AppHash: nil, // TODO
}
res := tapp.BeginBlock(abci.RequestBeginBlock{
Hash: nil, // TODO
Header: header,
AbsentValidators: nil, // TODO
ByzantineValidators: nil, // TODO
})
tapp.ResponseBeginBlock = &res
return
}
// kill resources used by basecapp
func (tapp *TestApp) Close() {
tapp.db.Close()
}
func (tapp *TestApp) ensureBeginBlock() {
if tapp.header == nil {
panic("TestApp.header was nil, call TestApp.RunBeginBlock()")
}
}
// run tx through CheckTx of TestApp
func (tapp *TestApp) RunCheckTx(tx sdk.Tx) sdk.Result {
tapp.ensureBeginBlock()
return tapp.BaseApp.runTx(true, nil, tx)
}
// run tx through DeliverTx of TestApp
func (tapp *TestApp) RunDeliverTx(tx sdk.Tx) sdk.Result {
tapp.ensureBeginBlock()
return tapp.BaseApp.runTx(false, nil, tx)
}
// run tx through CheckTx of TestApp
// NOTE: Skips authentication by wrapping msg in TestTx{}.
func (tapp *TestApp) RunCheckMsg(msg sdk.Msg) sdk.Result {
var tx = testtx.TestTx{msg}
return tapp.RunCheckTx(tx)
}
// run tx through DeliverTx of TestApp
// NOTE: Skips authentication by wrapping msg in TestTx{}.
func (tapp *TestApp) RunDeliverMsg(msg sdk.Msg) sdk.Result {
var tx = testtx.TestTx{msg}
return tapp.RunDeliverTx(tx)
}
// return the commited multistore
func (tapp *TestApp) CommitMultiStore() sdk.CommitMultiStore {
return tapp.BaseApp.cms
}
// return a cache-wrap CheckTx state of multistore
func (tapp *TestApp) MultiStoreCheck() sdk.MultiStore {
return tapp.BaseApp.msCheck
}
// return a cache-wrap DeliverTx state of multistore
func (tapp *TestApp) MultiStoreDeliver() sdk.MultiStore {
return tapp.BaseApp.msDeliver
}

6
types/abci.go Normal file
View File

@ -0,0 +1,6 @@
package types
import abci "github.com/tendermint/abci/types"
// initialize application state at genesis
type InitChainer func(ctx Context, req abci.RequestInitChain) Error

View File

@ -1,6 +0,0 @@
package types
import "encoding/json"
// function variable used to initialize application state at genesis
type InitStater func(ctx Context, state json.RawMessage) Error