From 33c829f99a1e777016317e7036076f8b7f3bbd52 Mon Sep 17 00:00:00 2001 From: Steven Landers Date: Thu, 4 Jan 2024 10:58:37 -0500 Subject: [PATCH] [EVM] Add pending nonce support (#390) - Adding an expiration handler callback that lets the mempool - https://github.com/sei-protocol/sei-tendermint/pull/179 - e2e testing with hardhat tests --- baseapp/abci.go | 5 +++-- baseapp/baseapp.go | 14 ++++++++------ baseapp/test_helpers.go | 6 +++--- go.mod | 2 +- go.sum | 4 ++-- types/accesscontrol/resource.go | 1 + types/context.go | 10 ++++++++++ 7 files changed, 28 insertions(+), 14 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index cfa5cf9f1..9bde5060c 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -226,7 +226,7 @@ func (app *BaseApp) CheckTx(ctx context.Context, req *abci.RequestCheckTx) (*abc res := sdkerrors.ResponseCheckTx(err, 0, 0, app.trace) return &abci.ResponseCheckTxV2{ResponseCheckTx: &res}, err } - gInfo, result, _, priority, pendingTxChecker, err := app.runTx(sdkCtx, mode, tx, sha256.Sum256(req.Tx)) + gInfo, result, _, priority, pendingTxChecker, expireTxHandler, err := app.runTx(sdkCtx, mode, tx, sha256.Sum256(req.Tx)) if err != nil { res := sdkerrors.ResponseCheckTx(err, gInfo.GasWanted, gInfo.GasUsed, app.trace) return &abci.ResponseCheckTxV2{ResponseCheckTx: &res}, err @@ -241,6 +241,7 @@ func (app *BaseApp) CheckTx(ctx context.Context, req *abci.RequestCheckTx) (*abc res.IsPendingTransaction = true res.Checker = pendingTxChecker } + res.ExpireTxHandler = expireTxHandler return res, nil } @@ -270,7 +271,7 @@ func (app *BaseApp) DeliverTx(ctx sdk.Context, req abci.RequestDeliverTx, tx sdk telemetry.SetGauge(float32(gInfo.GasWanted), "tx", "gas", "wanted") }() - gInfo, result, anteEvents, _, _, err := app.runTx(ctx.WithTxBytes(req.Tx).WithVoteInfos(app.voteInfos), runTxModeDeliver, tx, checksum) + gInfo, result, anteEvents, _, _, _, err := app.runTx(ctx.WithTxBytes(req.Tx).WithVoteInfos(app.voteInfos), runTxModeDeliver, tx, checksum) if err != nil { resultStr = "failed" // if we have a result, use those events instead of just the anteEvents diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index d5fc42d82..66c8f35f1 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -828,6 +828,7 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, tx sdk.Tx, checksum [ anteEvents []abci.Event, priority int64, pendingTxChecker abci.PendingTxChecker, + expireHandler abci.ExpireTxHandler, err error, ) { defer telemetry.MeasureThroughputSinceWithLabels( @@ -863,7 +864,7 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, tx sdk.Tx, checksum [ // only run the tx if there is block gas remaining if mode == runTxModeDeliver && ctx.BlockGasMeter().IsOutOfGas() { - return gInfo, nil, nil, -1, nil, sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "no block gas left to run tx") + return gInfo, nil, nil, -1, nil, nil, sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "no block gas left to run tx") } defer func() { @@ -900,13 +901,13 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, tx sdk.Tx, checksum [ } if tx == nil { - return sdk.GasInfo{}, nil, nil, 0, nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx decode error") + return sdk.GasInfo{}, nil, nil, 0, nil, nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx decode error") } msgs := tx.GetMsgs() if err := validateBasicTxMsgs(msgs); err != nil { - return sdk.GasInfo{}, nil, nil, 0, nil, err + return sdk.GasInfo{}, nil, nil, 0, nil, nil, err } if app.anteHandler != nil { @@ -948,7 +949,7 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, tx sdk.Tx, checksum [ // GasMeter expected to be set in AnteHandler gasWanted = ctx.GasMeter().Limit() if err != nil { - return gInfo, nil, nil, 0, nil, err + return gInfo, nil, nil, 0, nil, nil, err } // Dont need to validate in checkTx mode @@ -963,12 +964,13 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, tx sdk.Tx, checksum [ op.EmitValidationFailMetrics() } errMessage := fmt.Sprintf("Invalid Concurrent Execution antehandler missing %d access operations", len(missingAccessOps)) - return gInfo, nil, nil, 0, nil, sdkerrors.Wrap(sdkerrors.ErrInvalidConcurrencyExecution, errMessage) + return gInfo, nil, nil, 0, nil, nil, sdkerrors.Wrap(sdkerrors.ErrInvalidConcurrencyExecution, errMessage) } } priority = ctx.Priority() pendingTxChecker = ctx.PendingTxChecker() + expireHandler = ctx.ExpireTxHandler() msCache.Write() anteEvents = events.ToABCIEvents() anteSpan.End() @@ -998,7 +1000,7 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, tx sdk.Tx, checksum [ if ctx.CheckTxCallback() != nil { ctx.CheckTxCallback()(err) } - return gInfo, result, anteEvents, priority, pendingTxChecker, err + return gInfo, result, anteEvents, priority, pendingTxChecker, expireHandler, err } // runMsgs iterates through a list of messages and executes them with the provided diff --git a/baseapp/test_helpers.go b/baseapp/test_helpers.go index 7652b078e..1cc05327a 100644 --- a/baseapp/test_helpers.go +++ b/baseapp/test_helpers.go @@ -17,7 +17,7 @@ func (app *BaseApp) Check(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *sdk return sdk.GasInfo{}, nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } ctx := app.checkState.ctx.WithTxBytes(bz).WithVoteInfos(app.voteInfos).WithConsensusParams(app.GetConsensusParams(app.checkState.ctx)) - gasInfo, result, _, _, _, err := app.runTx(ctx, runTxModeCheck, tx, sha256.Sum256(bz)) + gasInfo, result, _, _, _, _, err := app.runTx(ctx, runTxModeCheck, tx, sha256.Sum256(bz)) if len(ctx.MultiStore().GetEvents()) > 0 { panic("Expected checkTx events to be empty") } @@ -31,7 +31,7 @@ func (app *BaseApp) Simulate(txBytes []byte) (sdk.GasInfo, *sdk.Result, error) { if err != nil { return sdk.GasInfo{}, nil, err } - gasInfo, result, _, _, _, err := app.runTx(ctx, runTxModeSimulate, tx, sha256.Sum256(txBytes)) + gasInfo, result, _, _, _, _, err := app.runTx(ctx, runTxModeSimulate, tx, sha256.Sum256(txBytes)) if len(ctx.MultiStore().GetEvents()) > 0 { panic("Expected simulate events to be empty") } @@ -49,7 +49,7 @@ func (app *BaseApp) Deliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *s if err != nil { return sdk.GasInfo{}, &sdk.Result{}, err } - gasInfo, result, _, _, _, err := app.runTx(ctx, runTxModeDeliver, decoded, sha256.Sum256(bz)) + gasInfo, result, _, _, _, _, err := app.runTx(ctx, runTxModeDeliver, decoded, sha256.Sum256(bz)) return gasInfo, result, err } diff --git a/go.mod b/go.mod index e0de340d2..0f2efc22c 100644 --- a/go.mod +++ b/go.mod @@ -183,7 +183,7 @@ replace ( github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.24 // Latest goleveldb is broken, we have to stick to this version github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.2.30-evm-2 + github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.2.35-evm-rebase // latest grpc doesn't work with with our modified proto compiler, so we need to enforce // the following version across all dependencies. google.golang.org/grpc => google.golang.org/grpc v1.33.2 diff --git a/go.sum b/go.sum index c43eb3a15..336fb7cc2 100644 --- a/go.sum +++ b/go.sum @@ -785,8 +785,8 @@ github.com/sei-protocol/sei-db v0.0.24 h1:rSidZZ4GNEJRY+0gm5+RioNqmYiOiPaZuDQ+vI github.com/sei-protocol/sei-db v0.0.24/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= github.com/sei-protocol/sei-iavl v0.1.7-seidb-1 h1:Acsjnanr8vhRZ5Dbv5sYnxDa8ibheXrlqLtbsUmLGEo= github.com/sei-protocol/sei-iavl v0.1.7-seidb-1/go.mod h1:7PfkEVT5dcoQE+s/9KWdoXJ8VVVP1QpYYPLdxlkSXFk= -github.com/sei-protocol/sei-tendermint v0.2.30-evm-2 h1:ibEV/DNT/5zO+A1+pP0Di96raadNv33ieOtMAn/iEr8= -github.com/sei-protocol/sei-tendermint v0.2.30-evm-2/go.mod h1:+BtDvAwTkE64BlxzpH9ZP7S6vUYT9wRXiZa/WW8/o4g= +github.com/sei-protocol/sei-tendermint v0.2.35-evm-rebase h1:qcYyQoa56KaMfH3EH3eiICxq9LgPVETBw3gzBehdKIA= +github.com/sei-protocol/sei-tendermint v0.2.35-evm-rebase/go.mod h1:4LSlJdhl3nf3OmohliwRNUFLOB1XWlrmSodrIP7fLh4= github.com/sei-protocol/sei-tm-db v0.0.5 h1:3WONKdSXEqdZZeLuWYfK5hP37TJpfaUa13vAyAlvaQY= github.com/sei-protocol/sei-tm-db v0.0.5/go.mod h1:Cpa6rGyczgthq7/0pI31jys2Fw0Nfrc+/jKdP1prVqY= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= diff --git a/types/accesscontrol/resource.go b/types/accesscontrol/resource.go index aa717e3e8..72a1afa65 100644 --- a/types/accesscontrol/resource.go +++ b/types/accesscontrol/resource.go @@ -22,6 +22,7 @@ var ResourceTree = map[ResourceType]TreeNode{ ResourceType_KV_FEEGRANT, ResourceType_KV_SLASHING, ResourceType_KV_BANK_DEFERRED, + ResourceType_KV_EVM, }}, ResourceType_Mem: {ResourceType_ANY, []ResourceType{ ResourceType_DexMem, diff --git a/types/context.go b/types/context.go index 527a2f210..6382df0d7 100644 --- a/types/context.go +++ b/types/context.go @@ -42,6 +42,7 @@ type Context struct { priority int64 // The tx priority, only relevant in CheckTx pendingTxChecker abci.PendingTxChecker // Checker for pending transaction, only relevant in CheckTx checkTxCallback func(error) // callback to make at the end of CheckTx. Input param is the error (nil-able) of `runMsgs` + expireTxHandler func() // callback that the mempool invokes when a tx is expired txBlockingChannels acltypes.MessageAccessOpsChannelMapping txCompletionChannels acltypes.MessageAccessOpsChannelMapping @@ -118,6 +119,10 @@ func (c Context) Priority() int64 { return c.priority } +func (c Context) ExpireTxHandler() abci.ExpireTxHandler { + return c.expireTxHandler +} + func (c Context) PendingTxChecker() abci.PendingTxChecker { return c.pendingTxChecker } @@ -369,6 +374,11 @@ func (c Context) WithCheckTxCallback(checkTxCallback func(error)) Context { return c } +func (c Context) WithExpireTxHandler(expireTxHandler func()) Context { + c.expireTxHandler = expireTxHandler + return c +} + // TODO: remove??? func (c Context) IsZero() bool { return c.ms == nil