refactor(baseapp): create checktx handler (#24069)

Co-authored-by: Alex | Interchain Labs <alex@interchainlabs.io>
Co-authored-by: Tyler <48813565+technicallyty@users.noreply.github.com>
This commit is contained in:
Hoang Do
2025-03-29 19:45:41 +00:00
committed by GitHub
co-authored by Alex | Interchain Labs Tyler
parent d68d169a63
commit 4f445ed933
8 changed files with 104 additions and 23 deletions
+19 -10
View File
@@ -351,18 +351,27 @@ func (app *BaseApp) CheckTx(req *abci.RequestCheckTx) (*abci.ResponseCheckTx, er
return nil, fmt.Errorf("unknown RequestCheckTx type: %s", req.Type)
}
gInfo, result, anteEvents, err := app.runTx(mode, req.Tx)
if err != nil {
return sdkerrors.ResponseCheckTxWithEvents(err, gInfo.GasWanted, gInfo.GasUsed, anteEvents, app.trace), nil
if app.checkTxHandler == nil {
gInfo, result, anteEvents, err := app.runTx(mode, req.Tx, nil)
if err != nil {
return sdkerrors.ResponseCheckTxWithEvents(err, gInfo.GasWanted, gInfo.GasUsed, anteEvents, app.trace), nil
}
return &abci.ResponseCheckTx{
GasWanted: int64(gInfo.GasWanted), // TODO: Should type accept unsigned ints?
GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints?
Log: result.Log,
Data: result.Data,
Events: sdk.MarkEventsToIndex(result.Events, app.indexEvents),
}, nil
}
return &abci.ResponseCheckTx{
GasWanted: int64(gInfo.GasWanted), // TODO: Should type accept unsigned ints?
GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints?
Log: result.Log,
Data: result.Data,
Events: sdk.MarkEventsToIndex(result.Events, app.indexEvents),
}, nil
// Create wrapper to avoid users overriding the execution mode
runTx := func(txBytes []byte, tx sdk.Tx) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) {
return app.runTx(mode, txBytes, tx)
}
return app.checkTxHandler(runTx, req)
}
// PrepareProposal implements the PrepareProposal ABCI method and returns a
+1 -1
View File
@@ -926,7 +926,7 @@ func TestABCI_InvalidTransaction(t *testing.T) {
_, _, err := suite.baseApp.SimDeliver(suite.txConfig.TxEncoder(), tx)
require.Error(t, err)
space, code, _ := errorsmod.ABCIInfo(err, false)
require.EqualValues(t, sdkerrors.ErrTxDecode.ABCICode(), code)
require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), code)
require.EqualValues(t, sdkerrors.ErrTxDecode.Codespace(), space)
}
}
+13 -8
View File
@@ -79,6 +79,7 @@ type BaseApp struct {
anteHandler sdk.AnteHandler // ante handler for fee and auth
postHandler sdk.PostHandler // post handler, optional
checkTxHandler sdk.CheckTxHandler // ABCI CheckTx handler
initChainer sdk.InitChainer // ABCI InitChain handler
preBlocker sdk.PreBlocker // logic to run before BeginBlocker
beginBlocker sdk.BeginBlocker // (legacy ABCI) BeginBlock handler
@@ -693,7 +694,6 @@ func (app *BaseApp) getContextForTx(mode execMode, txBytes []byte) sdk.Context {
// a branched multi-store.
func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context, storetypes.CacheMultiStore) {
ms := ctx.MultiStore()
// TODO: https://github.com/cosmos/cosmos-sdk/issues/2824
msCache := ms.CacheMultiStore()
if msCache.TracingEnabled() {
msCache = msCache.SetTracingContext(
@@ -769,7 +769,7 @@ func (app *BaseApp) deliverTx(tx []byte) *abci.ExecTxResult {
telemetry.SetGauge(float32(gInfo.GasWanted), "tx", "gas", "wanted")
}()
gInfo, result, anteEvents, err := app.runTx(execModeFinalize, tx)
gInfo, result, anteEvents, err := app.runTx(execModeFinalize, tx, nil)
if err != nil {
resultStr = "failed"
resp = sdkerrors.ResponseExecTxResultWithEvents(
@@ -826,7 +826,9 @@ func (app *BaseApp) endBlock(_ context.Context) (sdk.EndBlock, error) {
// Note, gas execution info is always returned. A reference to a Result is
// 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) {
// both txbytes and the decoded tx are passed to runTx to avoid the state machine encoding the tx and decoding the transaction twice
// passing the decoded tx to runTX is optional, it will be decoded if the tx is nil
func (app *BaseApp) runTx(mode execMode, txBytes []byte, tx sdk.Tx) (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.
@@ -874,9 +876,12 @@ func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, res
defer consumeBlockGas()
}
tx, err := app.txDecoder(txBytes)
if err != nil {
return sdk.GasInfo{}, nil, nil, err
// if the transaction is not decoded, decode it here
if tx == nil {
tx, err = app.txDecoder(txBytes)
if err != nil {
return sdk.GasInfo{GasUsed: 0, GasWanted: 0}, nil, nil, sdkerrors.ErrTxDecode.Wrap(err.Error())
}
}
msgs := tx.GetMsgs()
@@ -1115,7 +1120,7 @@ func (app *BaseApp) PrepareProposalVerifyTx(tx sdk.Tx) ([]byte, error) {
return nil, err
}
_, _, _, err = app.runTx(execModePrepareProposal, bz)
_, _, _, err = app.runTx(execModePrepareProposal, bz, tx)
if err != nil {
return nil, err
}
@@ -1134,7 +1139,7 @@ func (app *BaseApp) ProcessProposalVerifyTx(txBz []byte) (sdk.Tx, error) {
return nil, err
}
_, _, _, err = app.runTx(execModeProcessProposal, txBz)
_, _, _, err = app.runTx(execModeProcessProposal, txBz, tx)
if err != nil {
return nil, err
}
+9
View File
@@ -350,6 +350,15 @@ func (app *BaseApp) SetPrepareProposal(handler sdk.PrepareProposalHandler) {
app.prepareProposal = handler
}
// SetCheckTx sets the checkTx function for the BaseApp.
func (app *BaseApp) SetCheckTxHandler(handler sdk.CheckTxHandler) {
if app.sealed {
panic("SetCheckTxHandler() on sealed BaseApp")
}
app.checkTxHandler = handler
}
func (app *BaseApp) SetExtendVoteHandler(handler sdk.ExtendVoteHandler) {
if app.sealed {
panic("SetExtendVoteHandler() on sealed BaseApp")
+4 -4
View File
@@ -19,13 +19,13 @@ func (app *BaseApp) SimCheck(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *
return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err)
}
gasInfo, result, _, err := app.runTx(execModeCheck, bz)
gasInfo, result, _, err := app.runTx(execModeCheck, bz, tx)
return gasInfo, result, err
}
// Simulate executes a tx in simulate mode to get result and gas info.
func (app *BaseApp) Simulate(txBytes []byte) (sdk.GasInfo, *sdk.Result, error) {
gasInfo, result, _, err := app.runTx(execModeSimulate, txBytes)
gasInfo, result, _, err := app.runTx(execModeSimulate, txBytes, nil)
return gasInfo, result, err
}
@@ -36,7 +36,7 @@ func (app *BaseApp) SimDeliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo,
return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err)
}
gasInfo, result, _, err := app.runTx(execModeFinalize, bz)
gasInfo, result, _, err := app.runTx(execModeFinalize, bz, tx)
return gasInfo, result, err
}
@@ -47,7 +47,7 @@ func (app *BaseApp) SimTxFinalizeBlock(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.
return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err)
}
gasInfo, result, _, err := app.runTx(execModeFinalize, bz)
gasInfo, result, _, err := app.runTx(execModeFinalize, bz, tx)
return gasInfo, result, err
}