Clean up Context/MultiStore usage in BaseApp (#2847)

This commit is contained in:
Jae Kwon 2018-11-20 01:06:14 -08:00 committed by GitHub
parent 6e813ab3a8
commit 47eed3958b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 37 deletions

View File

@ -200,6 +200,10 @@ func (st *state) CacheMultiStore() sdk.CacheMultiStore {
return st.ms.CacheMultiStore() return st.ms.CacheMultiStore()
} }
func (st *state) Context() sdk.Context {
return st.ctx
}
func (app *BaseApp) setCheckState(header abci.Header) { func (app *BaseApp) setCheckState(header abci.Header) {
ms := app.cms.CacheMultiStore() ms := app.cms.CacheMultiStore()
app.checkState = &state{ app.checkState = &state{
@ -383,6 +387,7 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res
return sdk.ErrUnknownRequest(fmt.Sprintf("no custom querier found for route %s", path[1])).QueryResult() return sdk.ErrUnknownRequest(fmt.Sprintf("no custom querier found for route %s", path[1])).QueryResult()
} }
// Cache wrap the commit-multistore for safety.
ctx := sdk.NewContext(app.cms.CacheMultiStore(), app.checkState.ctx.BlockHeader(), true, app.Logger). ctx := sdk.NewContext(app.cms.CacheMultiStore(), app.checkState.ctx.BlockHeader(), true, app.Logger).
WithMinimumFees(app.minimumFees) WithMinimumFees(app.minimumFees)
@ -501,14 +506,14 @@ func validateBasicTxMsgs(msgs []sdk.Msg) sdk.Error {
return nil return nil
} }
// retrieve the context for the ante handler and store the tx bytes; store // retrieve the context for the tx w/ txBytes and other memoized values.
// the vote infos if the tx runs within the deliverTx() state. func (app *BaseApp) getContextForTx(mode runTxMode, txBytes []byte) (ctx sdk.Context) {
func (app *BaseApp) getContextForAnte(mode runTxMode, txBytes []byte) (ctx sdk.Context) { ctx = app.getState(mode).ctx.
ctx = app.getState(mode).ctx.WithTxBytes(txBytes) WithTxBytes(txBytes).
if mode == runTxModeDeliver { WithVoteInfos(app.voteInfos)
ctx = ctx.WithVoteInfos(app.voteInfos) if mode == runTxModeSimulate {
ctx, _ = ctx.CacheContext()
} }
return return
} }
@ -578,21 +583,14 @@ func (app *BaseApp) getState(mode runTxMode) *state {
return app.deliverState return app.deliverState
} }
func (app *BaseApp) initializeContext(ctx sdk.Context, mode runTxMode) sdk.Context { // cacheTxContext returns a new context based off of the provided context with
if mode == runTxModeSimulate { // a cache wrapped multi-store.
ctx = ctx.WithMultiStore(app.getState(runTxModeSimulate).CacheMultiStore()) func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (
} sdk.Context, sdk.CacheMultiStore) {
return ctx
}
// cacheTxContext returns a new context based off of the provided context with a ms := ctx.MultiStore()
// cache wrapped multi-store and the store itself to allow the caller to write // TODO: https://github.com/cosmos/cosmos-sdk/issues/2824
// changes from the cached multi-store. msCache := ms.CacheMultiStore()
func (app *BaseApp) cacheTxContext(
ctx sdk.Context, txBytes []byte, mode runTxMode,
) (sdk.Context, sdk.CacheMultiStore) {
msCache := app.getState(mode).CacheMultiStore()
if msCache.TracingEnabled() { if msCache.TracingEnabled() {
msCache = msCache.WithTracingContext( msCache = msCache.WithTracingContext(
sdk.TraceContext( sdk.TraceContext(
@ -616,8 +614,8 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
// meter so we initialize upfront. // meter so we initialize upfront.
var gasWanted uint64 var gasWanted uint64
ctx := app.getContextForAnte(mode, txBytes) ctx := app.getContextForTx(mode, txBytes)
ctx = app.initializeContext(ctx, mode) ms := ctx.MultiStore()
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@ -651,31 +649,37 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
// NOTE: Alternatively, we could require that anteHandler ensures that // NOTE: Alternatively, we could require that anteHandler ensures that
// writes do not happen if aborted/failed. This may have some // writes do not happen if aborted/failed. This may have some
// performance benefits, but it'll be more difficult to get right. // performance benefits, but it'll be more difficult to get right.
anteCtx, msCache = app.cacheTxContext(ctx, txBytes, mode) anteCtx, msCache = app.cacheTxContext(ctx, txBytes)
newCtx, result, abort := app.anteHandler(anteCtx, tx, (mode == runTxModeSimulate)) newCtx, result, abort := app.anteHandler(anteCtx, tx, (mode == runTxModeSimulate))
if abort { if abort {
return result return result
} }
if !newCtx.IsZero() { if !newCtx.IsZero() {
ctx = newCtx // At this point, newCtx.MultiStore() is cache wrapped,
// or something else replaced by anteHandler.
// We want the original ms, not one which was cache-wrapped
// for the ante handler.
ctx = newCtx.WithMultiStore(ms)
} }
msCache.Write() msCache.Write()
gasWanted = result.GasWanted gasWanted = result.GasWanted
} }
if mode == runTxModeSimulate { if mode == runTxModeCheck {
result = app.runMsgs(ctx, msgs, mode)
result.GasWanted = gasWanted
return return
} }
// Create a new context based off of the existing context with a cache wrapped // Create a new context based off of the existing context with a cache wrapped
// multi-store in case message processing fails. // multi-store in case message processing fails.
runMsgCtx, msCache := app.cacheTxContext(ctx, txBytes, mode) runMsgCtx, msCache := app.cacheTxContext(ctx, txBytes)
result = app.runMsgs(runMsgCtx, msgs, mode) result = app.runMsgs(runMsgCtx, msgs, mode)
result.GasWanted = gasWanted result.GasWanted = gasWanted
if mode == runTxModeSimulate {
return
}
// only update state if all messages pass // only update state if all messages pass
if result.IsOK() { if result.IsOK() {
msCache.Write() msCache.Write()

View File

@ -11,6 +11,8 @@ import (
// cacheMultiStore holds many cache-wrapped stores. // cacheMultiStore holds many cache-wrapped stores.
// Implements MultiStore. // Implements MultiStore.
// NOTE: a cacheMultiStore (and MultiStores in general) should never expose the
// keys for the substores.
type cacheMultiStore struct { type cacheMultiStore struct {
db CacheKVStore db CacheKVStore
stores map[StoreKey]CacheWrap stores map[StoreKey]CacheWrap

View File

@ -73,12 +73,12 @@ func (c Context) Value(key interface{}) interface{} {
// KVStore fetches a KVStore from the MultiStore. // KVStore fetches a KVStore from the MultiStore.
func (c Context) KVStore(key StoreKey) KVStore { func (c Context) KVStore(key StoreKey) KVStore {
return c.multiStore().GetKVStore(key).Gas(c.GasMeter(), cachedKVGasConfig) return c.MultiStore().GetKVStore(key).Gas(c.GasMeter(), cachedKVGasConfig)
} }
// TransientStore fetches a TransientStore from the MultiStore. // TransientStore fetches a TransientStore from the MultiStore.
func (c Context) TransientStore(key StoreKey) KVStore { func (c Context) TransientStore(key StoreKey) KVStore {
return c.multiStore().GetKVStore(key).Gas(c.GasMeter(), cachedTransientGasConfig) return c.MultiStore().GetKVStore(key).Gas(c.GasMeter(), cachedTransientGasConfig)
} }
//---------------------------------------- //----------------------------------------
@ -143,10 +143,7 @@ const (
contextKeyMinimumFees contextKeyMinimumFees
) )
// NOTE: Do not expose MultiStore. func (c Context) MultiStore() MultiStore {
// MultiStore exposes all the keys.
// Instead, pass the context and the store key.
func (c Context) multiStore() MultiStore {
return c.Value(contextKeyMultiStore).(MultiStore) return c.Value(contextKeyMultiStore).(MultiStore)
} }
@ -174,7 +171,9 @@ func (c Context) IsCheckTx() bool { return c.Value(contextKeyIsCheckTx).(bool) }
func (c Context) MinimumFees() Coins { return c.Value(contextKeyMinimumFees).(Coins) } func (c Context) MinimumFees() Coins { return c.Value(contextKeyMinimumFees).(Coins) }
func (c Context) WithMultiStore(ms MultiStore) Context { return c.withValue(contextKeyMultiStore, ms) } func (c Context) WithMultiStore(ms MultiStore) Context {
return c.withValue(contextKeyMultiStore, ms)
}
func (c Context) WithBlockHeader(header abci.Header) Context { func (c Context) WithBlockHeader(header abci.Header) Context {
var _ proto.Message = &header // for cloning. var _ proto.Message = &header // for cloning.
@ -232,7 +231,7 @@ func (c Context) WithMinimumFees(minFees Coins) Context {
// Cache the multistore and return a new cached context. The cached context is // Cache the multistore and return a new cached context. The cached context is
// written to the context when writeCache is called. // written to the context when writeCache is called.
func (c Context) CacheContext() (cc Context, writeCache func()) { func (c Context) CacheContext() (cc Context, writeCache func()) {
cms := c.multiStore().CacheMultiStore() cms := c.MultiStore().CacheMultiStore()
cc = c.WithMultiStore(cms) cc = c.WithMultiStore(cms)
return cc, cms.Write return cc, cms.Write
} }