From f07aee4ac9357f22878401d506ac583a830e1ae5 Mon Sep 17 00:00:00 2001 From: yihuang Date: Wed, 11 Sep 2024 16:44:50 +0800 Subject: [PATCH] Problem: tx executor can't do dependency analysis (#744) * Problem: tx executor can't do dependency analysis Solution: - change the api to allow static analysis on tx body * fix * changelog * cleanup * Update CHANGELOG.md Signed-off-by: yihuang --------- Signed-off-by: yihuang --- baseapp/abci.go | 8 ++++---- baseapp/baseapp.go | 27 ++++++++++++++++++--------- baseapp/genesis.go | 2 +- baseapp/txexecutor.go | 5 +++-- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index 1b0c12394299..3d3b6f11926e 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -842,8 +842,8 @@ func (app *BaseApp) internalFinalizeBlock(ctx context.Context, req *abci.Request func (app *BaseApp) executeTxs(ctx context.Context, txs [][]byte) ([]*abci.ExecTxResult, error) { if app.txExecutor != nil { - return app.txExecutor(ctx, len(txs), app.finalizeBlockState.ms, func(i int, ms storetypes.MultiStore, incarnationCache map[string]any) *abci.ExecTxResult { - return app.deliverTxWithMultiStore(txs[i], i, ms, incarnationCache) + return app.txExecutor(ctx, txs, app.finalizeBlockState.ms, func(i int, memTx sdk.Tx, ms storetypes.MultiStore, incarnationCache map[string]any) *abci.ExecTxResult { + return app.deliverTxWithMultiStore(txs[i], memTx, i, ms, incarnationCache) }) } @@ -851,8 +851,8 @@ func (app *BaseApp) executeTxs(ctx context.Context, txs [][]byte) ([]*abci.ExecT for i, rawTx := range txs { var response *abci.ExecTxResult - if _, err := app.txDecoder(rawTx); err == nil { - response = app.deliverTx(rawTx, i) + if memTx, err := app.txDecoder(rawTx); err == nil { + response = app.deliverTx(rawTx, memTx, i) } else { // In the case where a transaction included in a block proposal is malformed, // we still want to return a default response to comet. This is because comet diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 90953390b7f6..8702ec1d848c 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -768,11 +768,11 @@ func (app *BaseApp) beginBlock(_ *abci.RequestFinalizeBlock) (sdk.BeginBlock, er return resp, nil } -func (app *BaseApp) deliverTx(tx []byte, txIndex int) *abci.ExecTxResult { - return app.deliverTxWithMultiStore(tx, txIndex, nil, nil) +func (app *BaseApp) deliverTx(tx []byte, memTx sdk.Tx, txIndex int) *abci.ExecTxResult { + return app.deliverTxWithMultiStore(tx, memTx, txIndex, nil, nil) } -func (app *BaseApp) deliverTxWithMultiStore(tx []byte, txIndex int, txMultiStore storetypes.MultiStore, incarnationCache map[string]any) *abci.ExecTxResult { +func (app *BaseApp) deliverTxWithMultiStore(tx []byte, memTx sdk.Tx, txIndex int, txMultiStore storetypes.MultiStore, incarnationCache map[string]any) *abci.ExecTxResult { gInfo := sdk.GasInfo{} resultStr := "successful" @@ -785,7 +785,7 @@ func (app *BaseApp) deliverTxWithMultiStore(tx []byte, txIndex int, txMultiStore telemetry.SetGauge(float32(gInfo.GasWanted), "tx", "gas", "wanted") }() - gInfo, result, anteEvents, err := app.runTxWithMultiStore(execModeFinalize, tx, txIndex, txMultiStore, incarnationCache) + gInfo, result, anteEvents, err := app.runTxWithMultiStore(execModeFinalize, tx, memTx, txIndex, txMultiStore, incarnationCache) if err != nil { resultStr = "failed" resp = sdkerrors.ResponseExecTxResultWithEvents( @@ -843,10 +843,17 @@ func (app *BaseApp) endBlock(_ context.Context) (sdk.EndBlock, error) { // returned if the tx does not run out of gas and if all the messages are valid // and execute successfully. An error is returned otherwise. func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) { - return app.runTxWithMultiStore(mode, txBytes, -1, nil, nil) + return app.runTxWithMultiStore(mode, txBytes, nil, -1, nil, nil) } -func (app *BaseApp) runTxWithMultiStore(mode execMode, txBytes []byte, txIndex int, txMultiStore storetypes.MultiStore, incarnationCache map[string]any) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) { +func (app *BaseApp) runTxWithMultiStore( + mode execMode, + txBytes []byte, + tx sdk.Tx, + txIndex int, + txMultiStore storetypes.MultiStore, + incarnationCache map[string]any, +) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) { // NOTE: GasWanted should be returned by the AnteHandler. GasUsed is // determined by the GasMeter. We need access to the context to get the gas // meter, so we initialize upfront. @@ -898,9 +905,11 @@ func (app *BaseApp) runTxWithMultiStore(mode execMode, txBytes []byte, txIndex i defer consumeBlockGas() } - tx, err := app.txDecoder(txBytes) - if err != nil { - return sdk.GasInfo{}, nil, nil, err + if tx == nil { + tx, err = app.txDecoder(txBytes) + if err != nil { + return sdk.GasInfo{}, nil, nil, err + } } msgs := tx.GetMsgs() diff --git a/baseapp/genesis.go b/baseapp/genesis.go index e9f611772e08..562bdca3b276 100644 --- a/baseapp/genesis.go +++ b/baseapp/genesis.go @@ -13,7 +13,7 @@ var _ genesis.TxHandler = (*BaseApp)(nil) // ExecuteGenesisTx implements genesis.GenesisState from // cosmossdk.io/core/genesis to set initial state in genesis func (ba BaseApp) ExecuteGenesisTx(tx []byte) error { - res := ba.deliverTx(tx, -1) + res := ba.deliverTx(tx, nil, -1) if res.Code != types.CodeTypeOK { return errors.New(res.Log) diff --git a/baseapp/txexecutor.go b/baseapp/txexecutor.go index 82649036dba0..b09c204e06c0 100644 --- a/baseapp/txexecutor.go +++ b/baseapp/txexecutor.go @@ -4,13 +4,14 @@ import ( "context" abci "github.com/cometbft/cometbft/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" "cosmossdk.io/store/types" ) type TxExecutor func( ctx context.Context, - blockSize int, + block [][]byte, cms types.MultiStore, - deliverTxWithMultiStore func(int, types.MultiStore, map[string]any) *abci.ExecTxResult, + deliverTxWithMultiStore func(int, sdk.Tx, types.MultiStore, map[string]any) *abci.ExecTxResult, ) ([]*abci.ExecTxResult, error)