From 9908dd7bbf8dbc9492e92549bc0856c38625774b 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 0cdfef2ff2c7..c3a9a7b88a6f 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -845,8 +845,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) }) } @@ -854,8 +854,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 edabaf1fd689..e7e67bfa924e 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -770,11 +770,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" @@ -787,7 +787,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( @@ -845,10 +845,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. @@ -900,9 +907,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)