From c6182358ac280f70a5c5b6af56cbdb2b72353d13 Mon Sep 17 00:00:00 2001 From: yihuang Date: Fri, 8 Mar 2024 08:20:29 +0800 Subject: [PATCH] block-stm integration - patch tx response to fix tx index and log index - collect tx fee to temporary module account --- app/ante/handler_options.go | 1 - app/ante/interfaces.go | 2 - app/ante/setup.go | 38 -------- app/app.go | 27 ++++++ app/executor.go | 159 +++++++++++++++++++++++++++++++ go.mod | 16 ++-- go.sum | 36 +++---- gomod2nix.toml | 38 ++++---- server/config/config.go | 5 +- server/config/toml.go | 3 + server/flags/flags.go | 6 +- tests/importer/importer_test.go | 9 +- x/evm/keeper/abci.go | 14 +-- x/evm/keeper/bloom.go | 36 +++++++ x/evm/keeper/config.go | 3 +- x/evm/keeper/gas.go | 44 ++++++++- x/evm/keeper/keeper.go | 81 ++-------------- x/evm/keeper/msg_server.go | 3 - x/evm/keeper/state_transition.go | 21 +--- x/evm/keeper/utils.go | 15 --- x/evm/types/interfaces.go | 2 + x/evm/types/key.go | 4 - x/evm/types/response.go | 65 +++++++++++++ x/evm/types/utils_test.go | 8 +- 24 files changed, 413 insertions(+), 223 deletions(-) create mode 100644 app/executor.go create mode 100644 x/evm/keeper/bloom.go create mode 100644 x/evm/types/response.go diff --git a/app/ante/handler_options.go b/app/ante/handler_options.go index 2f005a0d62..4ce02166b6 100644 --- a/app/ante/handler_options.go +++ b/app/ante/handler_options.go @@ -86,7 +86,6 @@ func newEthAnteHandler(ctx sdk.Context, options HandlerOptions, extra ...sdk.Ant NewEthGasConsumeDecorator(options.EvmKeeper, options.MaxTxGasWanted, ethCfg, evmDenom, baseFee), NewEthIncrementSenderSequenceDecorator(options.AccountKeeper), // innermost AnteDecorator. NewGasWantedDecorator(options.FeeMarketKeeper, ethCfg), - NewEthEmitEventDecorator(options.EvmKeeper), // emit eth tx hash and index at the very last ante handler. } decorators = append(decorators, extra...) return sdk.ChainAnteDecorators(decorators...) diff --git a/app/ante/interfaces.go b/app/ante/interfaces.go index dc0c73cffa..0518c955c8 100644 --- a/app/ante/interfaces.go +++ b/app/ante/interfaces.go @@ -41,8 +41,6 @@ type EVMKeeper interface { DynamicFeeEVMKeeper DeductTxCostsFromUserBalance(ctx sdk.Context, fees sdk.Coins, from common.Address) error - ResetTransientGasUsed(ctx sdk.Context) - GetTxIndexTransient(ctx sdk.Context) uint64 } type protoTxProvider interface { diff --git a/app/ante/setup.go b/app/ante/setup.go index 8cad8eaa1f..72da48aa1d 100644 --- a/app/ante/setup.go +++ b/app/ante/setup.go @@ -18,7 +18,6 @@ package ante import ( "errors" "math/big" - "strconv" errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" @@ -53,46 +52,9 @@ func (esc EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul newCtx = ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()). WithKVGasConfig(storetypes.GasConfig{}). WithTransientKVGasConfig(storetypes.GasConfig{}) - - // Reset transient gas used to prepare the execution of current cosmos tx. - // Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs. - esc.evmKeeper.ResetTransientGasUsed(ctx) return next(newCtx, tx, simulate) } -// EthEmitEventDecorator emit events in ante handler in case of tx execution failed (out of block gas limit). -type EthEmitEventDecorator struct { - evmKeeper EVMKeeper -} - -// NewEthEmitEventDecorator creates a new EthEmitEventDecorator -func NewEthEmitEventDecorator(evmKeeper EVMKeeper) EthEmitEventDecorator { - return EthEmitEventDecorator{evmKeeper} -} - -// AnteHandle emits some basic events for the eth messages -func (eeed EthEmitEventDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - // After eth tx passed ante handler, the fee is deducted and nonce increased, it shouldn't be ignored by json-rpc, - // we need to emit some basic events at the very end of ante handler to be indexed by tendermint. - txIndex := eeed.evmKeeper.GetTxIndexTransient(ctx) - for i, msg := range tx.GetMsgs() { - msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) - if !ok { - return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil)) - } - - // emit ethereum tx hash as an event so that it can be indexed by Tendermint for query purposes - // it's emitted in ante handler, so we can query failed transaction (out of block gas limit). - ctx.EventManager().EmitEvent(sdk.NewEvent( - evmtypes.EventTypeEthereumTx, - sdk.NewAttribute(evmtypes.AttributeKeyEthereumTxHash, msgEthTx.Hash), - sdk.NewAttribute(evmtypes.AttributeKeyTxIndex, strconv.FormatUint(txIndex+uint64(i), 10)), - )) - } - - return next(ctx, tx, simulate) -} - // EthValidateBasicDecorator is adapted from ValidateBasicDecorator from cosmos-sdk, it ignores ErrNoSignatures type EthValidateBasicDecorator struct { evmParams *evmtypes.Params diff --git a/app/app.go b/app/app.go index a1678728cd..a85c7281e5 100644 --- a/app/app.go +++ b/app/app.go @@ -23,6 +23,7 @@ import ( "net/http" "os" "path/filepath" + "sort" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" @@ -392,6 +393,16 @@ func NewEthermintApp( memKeys: memKeys, } + app.SetDisableBlockGasMeter(true) + + executor := cast.ToString(appOpts.Get(srvflags.EVMBlockExecutor)) + if executor == "block-stm" { + workers := cast.ToInt(appOpts.Get(srvflags.EVMBlockSTMWorkers)) + app.SetTxExecutor(STMTxExecutor(app.GetStoreKeys(), workers)) + } else { + app.SetTxExecutor(DefaultTxExecutor) + } + // init params keeper and subspaces app.ParamsKeeper = initParamsKeeper(appCodec, cdc, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey]) @@ -1030,6 +1041,22 @@ func (app *EthermintApp) GetMemKey(storeKey string) *storetypes.MemoryStoreKey { return app.memKeys[storeKey] } +// GetStoreKeys returns all the stored store keys. +func (app *EthermintApp) GetStoreKeys() []storetypes.StoreKey { + keys := make([]storetypes.StoreKey, 0, len(app.keys)) + for _, key := range app.keys { + keys = append(keys, key) + } + for _, key := range app.tkeys { + keys = append(keys, key) + } + for _, key := range app.memKeys { + keys = append(keys, key) + } + sort.SliceStable(keys, func(i, j int) bool { return keys[i].Name() < keys[j].Name() }) + return keys +} + // GetSubspace returns a param subspace for a given module name. // // NOTE: This is solely to be used for testing purposes. diff --git a/app/executor.go b/app/executor.go new file mode 100644 index 0000000000..f60c108fce --- /dev/null +++ b/app/executor.go @@ -0,0 +1,159 @@ +package app + +import ( + "context" + "io" + + "cosmossdk.io/store/cachekv" + "cosmossdk.io/store/cachemulti" + "cosmossdk.io/store/tracekv" + storetypes "cosmossdk.io/store/types" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/cosmos-sdk/baseapp" + evmtypes "github.com/evmos/ethermint/x/evm/types" + block_stm "github.com/yihuang/go-block-stm" +) + +func DefaultTxExecutor(ctx context.Context, + blockSize int, + ms storetypes.MultiStore, + deliverTxWithMultiStore func(int, storetypes.MultiStore) *abci.ExecTxResult, +) ([]*abci.ExecTxResult, error) { + results := make([]*abci.ExecTxResult, blockSize) + for i := 0; i < blockSize; i++ { + results[i] = deliverTxWithMultiStore(i, ms) + } + return evmtypes.PatchTxResponses(results), nil +} + +func STMTxExecutor(stores []storetypes.StoreKey, workers int) baseapp.TxExecutor { + return func( + ctx context.Context, + blockSize int, + ms storetypes.MultiStore, + deliverTxWithMultiStore func(int, storetypes.MultiStore) *abci.ExecTxResult, + ) ([]*abci.ExecTxResult, error) { + if blockSize == 0 { + return nil, nil + } + results := make([]*abci.ExecTxResult, blockSize) + if err := block_stm.ExecuteBlock( + ctx, + blockSize, + stores, + stmMultiStoreWrapper{ms}, + workers, + func(txn block_stm.TxnIndex, ms block_stm.MultiStore) { + result := deliverTxWithMultiStore(int(txn), newMultiStoreWrapper(ms, stores)) + results[txn] = result + }, + ); err != nil { + return nil, err + } + + return evmtypes.PatchTxResponses(results), nil + } +} + +type storeWrapper struct { + block_stm.KVStore +} + +var ( + _ storetypes.Store = storeWrapper{} + _ storetypes.KVStore = storeWrapper{} +) + +func (s storeWrapper) GetStoreType() storetypes.StoreType { + return storetypes.StoreTypeIAVL +} + +func (s storeWrapper) CacheWrap() storetypes.CacheWrap { + return cachekv.NewStore(storetypes.KVStore(s)) +} + +func (s storeWrapper) CacheWrapWithTrace(w io.Writer, tc storetypes.TraceContext) storetypes.CacheWrap { + return cachekv.NewStore(tracekv.NewStore(s, w, tc)) +} + +type msWrapper struct { + block_stm.MultiStore + stores []storetypes.StoreKey + keysByName map[string]storetypes.StoreKey +} + +var _ storetypes.MultiStore = msWrapper{} + +func newMultiStoreWrapper(ms block_stm.MultiStore, stores []storetypes.StoreKey) msWrapper { + keysByName := make(map[string]storetypes.StoreKey) + for _, k := range stores { + keysByName[k.Name()] = k + } + return msWrapper{ms, stores, keysByName} +} + +func (ms msWrapper) GetStore(key storetypes.StoreKey) storetypes.Store { + return storetypes.Store(ms.GetKVStore(key)) +} + +func (ms msWrapper) GetKVStore(key storetypes.StoreKey) storetypes.KVStore { + return storeWrapper{ms.MultiStore.GetKVStore(key)} +} + +func (ms msWrapper) CacheMultiStore() storetypes.CacheMultiStore { + stores := make(map[storetypes.StoreKey]storetypes.CacheWrapper) + for _, k := range ms.stores { + store := ms.GetKVStore(k) + stores[k] = store + } + return cachemulti.NewStore(nil, stores, ms.keysByName, nil, nil) +} + +func (ms msWrapper) CacheMultiStoreWithVersion(_ int64) (storetypes.CacheMultiStore, error) { + panic("cannot branch cached multi-store with a version") +} + +// Implements CacheWrapper. +func (ms msWrapper) CacheWrap() storetypes.CacheWrap { + return ms.CacheMultiStore().(storetypes.CacheWrap) +} + +// CacheWrapWithTrace implements the CacheWrapper interface. +func (ms msWrapper) CacheWrapWithTrace(_ io.Writer, _ storetypes.TraceContext) storetypes.CacheWrap { + return ms.CacheWrap() +} + +// GetStoreType returns the type of the store. +func (ms msWrapper) GetStoreType() storetypes.StoreType { + return storetypes.StoreTypeMulti +} + +// LatestVersion returns the branch version of the store +func (ms msWrapper) LatestVersion() int64 { + panic("cannot get latest version from branch cached multi-store") +} + +// Implements interface MultiStore +func (ms msWrapper) SetTracer(w io.Writer) storetypes.MultiStore { + return nil +} + +// Implements interface MultiStore +func (ms msWrapper) SetTracingContext(storetypes.TraceContext) storetypes.MultiStore { + return nil +} + +// Implements interface MultiStore +func (ms msWrapper) TracingEnabled() bool { + return false +} + +type stmMultiStoreWrapper struct { + inner storetypes.MultiStore +} + +var _ block_stm.MultiStore = stmMultiStoreWrapper{} + +func (ms stmMultiStoreWrapper) GetKVStore(key storetypes.StoreKey) block_stm.KVStore { + return block_stm.KVStore(ms.inner.GetKVStore(key)) +} diff --git a/go.mod b/go.mod index 9174d04e29..d007ec9685 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/ethereum/go-ethereum v1.10.26 github.com/gogo/protobuf v1.3.2 - github.com/golang/protobuf v1.5.3 + github.com/golang/protobuf v1.5.4 github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 @@ -50,12 +50,13 @@ require ( github.com/tidwall/gjson v1.14.4 github.com/tidwall/sjson v1.2.5 github.com/tyler-smith/go-bip39 v1.1.0 + github.com/yihuang/go-block-stm v0.0.0-20240304045905-48d16c0e4681 golang.org/x/net v0.21.0 golang.org/x/sync v0.6.0 golang.org/x/text v0.14.0 google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 google.golang.org/grpc v1.62.0 - google.golang.org/protobuf v1.32.0 + google.golang.org/protobuf v1.33.0 sigs.k8s.io/yaml v1.4.0 ) @@ -220,12 +221,12 @@ require ( go.opentelemetry.io/otel/metric v1.22.0 // indirect go.opentelemetry.io/otel/trace v1.22.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.21.0 // indirect + golang.org/x/crypto v0.19.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/mod v0.15.0 // indirect - golang.org/x/oauth2 v0.17.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/term v0.18.0 // indirect + golang.org/x/oauth2 v0.16.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/term v0.17.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.18.0 // indirect google.golang.org/api v0.162.0 // indirect @@ -244,10 +245,11 @@ replace ( // use cosmos keyring github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 github.com/cockroachdb/pebble => github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 - github.com/cosmos/cosmos-sdk => github.com/mmsqe/cosmos-sdk v0.46.0-beta2.0.20240315010123-8531387f70f0 + github.com/cosmos/cosmos-sdk => github.com/yihuang/cosmos-sdk v0.43.0-beta1.0.20240317073920-e8d54831f9a9 github.com/ethereum/go-ethereum => github.com/crypto-org-chain/go-ethereum v1.10.20-0.20231207063621-43cf32d91c3e // Fix upstream GHSA-h395-qcrw-5vmq vulnerability. // TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409 github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.0 github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 + github.com/tidwall/btree => github.com/yihuang/btree v0.0.0-20240215071918-6726a9b22e40 ) diff --git a/go.sum b/go.sum index 41c73f7c7d..343f1d4f72 100644 --- a/go.sum +++ b/go.sum @@ -599,8 +599,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -876,8 +876,6 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= -github.com/mmsqe/cosmos-sdk v0.46.0-beta2.0.20240315010123-8531387f70f0 h1:l5y2mWuxNJXCQ8Z6O3Im/S4phdJpCByYrQGPFDqW6E0= -github.com/mmsqe/cosmos-sdk v0.46.0-beta2.0.20240315010123-8531387f70f0/go.mod h1:XDxLZycgyFXEBpgCdxOfYt5//bHCK6Z7b5FqkX6eV7M= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -1093,8 +1091,8 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= -github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= +github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= +github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -1127,6 +1125,12 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yihuang/btree v0.0.0-20240215071918-6726a9b22e40 h1:FPcNbZSQgK2d/Oj5tD4TwJM8ealdG4DLYvETLV9D5EE= +github.com/yihuang/btree v0.0.0-20240215071918-6726a9b22e40/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= +github.com/yihuang/cosmos-sdk v0.43.0-beta1.0.20240317073920-e8d54831f9a9 h1:jQV9X2iw848dPCdSYaIYbP3dFWxNwSWKo0yFtGwU4Pc= +github.com/yihuang/cosmos-sdk v0.43.0-beta1.0.20240317073920-e8d54831f9a9/go.mod h1:oV/k6GJgXV9QPoM2fsYDPPsyPBgQbdotv532O6Mz1OQ= +github.com/yihuang/go-block-stm v0.0.0-20240304045905-48d16c0e4681 h1:NRTXt16IYNBL0TXA5ctE+lwc49xQuMrozff/PZtnLH0= +github.com/yihuang/go-block-stm v0.0.0-20240304045905-48d16c0e4681/go.mod h1:EMX4xUF9OcXC9iS9d3TkEkT1Cv5bw5gVwGJB5BKRVyI= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1191,8 +1195,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1321,8 +1325,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1437,13 +1441,13 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1768,8 +1772,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/gomod2nix.toml b/gomod2nix.toml index f89507c54b..a63c19ea96 100644 --- a/gomod2nix.toml +++ b/gomod2nix.toml @@ -160,9 +160,9 @@ schema = 3 version = "v1.0.0-beta.4" hash = "sha256-5Kn82nsZfiEtuwhhLZqmMxdAY1tX/Fi3HJ0/MEaRohw=" [mod."github.com/cosmos/cosmos-sdk"] - version = "v0.46.0-beta2.0.20240315010123-8531387f70f0" - hash = "sha256-BMDRYiMyWid8ncLOg+AB7ZA2ZV/hDVAW0gPx/e24Q8Y=" - replaced = "github.com/mmsqe/cosmos-sdk" + version = "v0.43.0-beta1.0.20240317073920-e8d54831f9a9" + hash = "sha256-QRR5RH16KEOcYZqOBrC8Ax1Mo8SJ5eu1LVhY2g2d268=" + replaced = "github.com/yihuang/cosmos-sdk" [mod."github.com/cosmos/go-bip39"] version = "v1.0.0" hash = "sha256-Qm2aC2vaS8tjtMUbHmlBSagOSqbduEEDwc51qvQaBmA=" @@ -306,8 +306,8 @@ schema = 3 version = "v1.6.0" hash = "sha256-fWdnMQisRbiRzGT3ISrUHovquzLRHWvcv1JEsJFZRno=" [mod."github.com/golang/protobuf"] - version = "v1.5.3" - hash = "sha256-svogITcP4orUIsJFjMtp+Uv1+fKJv2Q5Zwf2dMqnpOQ=" + version = "v1.5.4" + hash = "sha256-N3+Lv9lEZjrdOWdQhFj6Y3Iap4rVLEQeI8/eFFyAMZ0=" [mod."github.com/golang/snappy"] version = "v0.0.5-0.20220116011046-fa5810519dcb" hash = "sha256-4GVLPBwJIXYFJU+Uvoa/sb5VHea7yJhwE7feABa7ucs=" @@ -565,8 +565,9 @@ schema = 3 version = "v0.16.0" hash = "sha256-JW4zO/0vMzf1dXLePOqaMtiLUZgNbuIseh9GV+jQlf0=" [mod."github.com/tidwall/btree"] - version = "v1.7.0" - hash = "sha256-bnr6c7a0nqo2HyGqxHk0kEZCEsjLYkPbAVY9WzaZ30o=" + version = "v0.0.0-20240215071918-6726a9b22e40" + hash = "sha256-s0olXV7w23o3UHCxlndyXFilL0tzbibxVecylN5a+LQ=" + replaced = "github.com/yihuang/btree" [mod."github.com/tidwall/gjson"] version = "v1.14.4" hash = "sha256-3DS2YNL95wG0qSajgRtIABD32J+oblaKVk8LIw+KSOc=" @@ -591,6 +592,9 @@ schema = 3 [mod."github.com/ulikunitz/xz"] version = "v0.5.11" hash = "sha256-SUyrjc2wyN3cTGKe5JdBEXjtZC1rJySRxJHVUZ59row=" + [mod."github.com/yihuang/go-block-stm"] + version = "v0.0.0-20240304045905-48d16c0e4681" + hash = "sha256-BYpBhCPtT4Bmws3K6acs+jzPxEM7hufAECz5oTtkKpY=" [mod."github.com/zondax/hid"] version = "v0.9.2" hash = "sha256-9h1gEJ/loyaJvu9AsmslztiA8U9ixDTC6TBw9lCU2BE=" @@ -622,8 +626,8 @@ schema = 3 version = "v1.11.0" hash = "sha256-Lb6rHHfR62Ozg2j2JZy3MKOMKdsfzd1IYTR57r3Mhp0=" [mod."golang.org/x/crypto"] - version = "v0.21.0" - hash = "sha256-Z4k1LvFh4Jai7HUe6TTuXSG3VnuiRpMwdARIdZZqSYk=" + version = "v0.19.0" + hash = "sha256-Vi6vY/eWNlYQ9l3Y+gA+X2+h2CmzEOrBRVFO/cnrPWc=" [mod."golang.org/x/exp"] version = "v0.0.0-20240222234643-814bf88cf225" hash = "sha256-DM6/KUjyqyuqXai7UH1vMsoKXQAlYfcHTwK1dHqjRAc=" @@ -634,17 +638,17 @@ schema = 3 version = "v0.21.0" hash = "sha256-LfiqMpPtqvW/eLkfx6Ebr5ksqKbQli6uq06c/+XrBsw=" [mod."golang.org/x/oauth2"] - version = "v0.17.0" - hash = "sha256-M2ZZQZt449RJL18YpzGiAiqfGsDVMsr1IVWbYp/G/go=" + version = "v0.16.0" + hash = "sha256-fJfS9dKaq82WaYSVWHMnxNLWH8+L4aip/C1AfJi4FFI=" [mod."golang.org/x/sync"] version = "v0.6.0" hash = "sha256-LLims/wjDZtIqlYCVHREewcUOX4hwRwplEuZKPOJ/HI=" [mod."golang.org/x/sys"] - version = "v0.18.0" - hash = "sha256-bIFhfFp7Sj0E1gcE3X3l/jecCfSRLgrkb8f0Yr6tVR0=" + version = "v0.17.0" + hash = "sha256-e0qnE+SitE02IzvnJKI4Uzpq9EOZY+zvE8Wf5b2e6Kg=" [mod."golang.org/x/term"] - version = "v0.18.0" - hash = "sha256-lpze9arFZIhBV8Ht3VZyoiUwqPkeH2IwfXt8M3xljiM=" + version = "v0.17.0" + hash = "sha256-lCo7WPHe8Q9q76f0D8FrfoX90MTvwa21O+Dwr1mOAcA=" [mod."golang.org/x/text"] version = "v0.14.0" hash = "sha256-yh3B0tom1RfzQBf1RNmfdNWF1PtiqxV41jW1GVS6JAg=" @@ -673,8 +677,8 @@ schema = 3 version = "v1.62.0" hash = "sha256-OnEEt6J1d9uQazORCpD6jbAKph8/dKlDHcUEEkLQyjQ=" [mod."google.golang.org/protobuf"] - version = "v1.32.0" - hash = "sha256-GJuTkMGHCzHbyK4yD5kY4oMn8wQWqgkeBK//yVDqHJk=" + version = "v1.33.0" + hash = "sha256-cWwQjtUwSIEkAlAadrlxK1PYZXTRrV4NKzt7xDpJgIU=" [mod."gopkg.in/ini.v1"] version = "v1.67.0" hash = "sha256-V10ahGNGT+NLRdKUyRg1dos5RxLBXBk1xutcnquc/+4=" diff --git a/server/config/config.go b/server/config/config.go index b7d78f7091..79acb7cdb2 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -123,7 +123,9 @@ type EVMConfig struct { // trace mode. Default: 'json'. Tracer string `mapstructure:"tracer"` // MaxTxGasWanted defines the gas wanted for each eth tx returned in ante handler in check tx mode. - MaxTxGasWanted uint64 `mapstructure:"max-tx-gas-wanted"` + MaxTxGasWanted uint64 `mapstructure:"max-tx-gas-wanted"` + BlockExecutor string `mapstructure:"block-executor"` + BlockSTMWorkers int `mapstructure:"block-stm-workers"` } // JSONRPCConfig defines configuration for the EVM RPC server. @@ -238,6 +240,7 @@ func DefaultEVMConfig() *EVMConfig { return &EVMConfig{ Tracer: DefaultEVMTracer, MaxTxGasWanted: DefaultMaxTxGasWanted, + BlockExecutor: "sequential", } } diff --git a/server/config/toml.go b/server/config/toml.go index 84295be973..cfda75a20d 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -31,6 +31,9 @@ tracer = "{{ .EVM.Tracer }}" # MaxTxGasWanted defines the gas wanted for each eth tx returned in ante handler in check tx mode. max-tx-gas-wanted = {{ .EVM.MaxTxGasWanted }} +block-executor = {{ .EVM.BlockExecutor }} +block-stm-workers = {{ .EVM.BlockSTMWorkers }} + ############################################################################### ### JSON RPC Configuration ### ############################################################################### diff --git a/server/flags/flags.go b/server/flags/flags.go index 502cc7f4f6..1cf5916782 100644 --- a/server/flags/flags.go +++ b/server/flags/flags.go @@ -76,8 +76,10 @@ const ( // EVM flags const ( - EVMTracer = "evm.tracer" - EVMMaxTxGasWanted = "evm.max-tx-gas-wanted" + EVMTracer = "evm.tracer" + EVMMaxTxGasWanted = "evm.max-tx-gas-wanted" + EVMBlockExecutor = "evm.block-executor" + EVMBlockSTMWorkers = "evm.block-stm-workers" ) // TLS flags diff --git a/tests/importer/importer_test.go b/tests/importer/importer_test.go index b60f602aa8..9135ad43dc 100644 --- a/tests/importer/importer_test.go +++ b/tests/importer/importer_test.go @@ -144,10 +144,9 @@ func (suite *ImporterTestSuite) TestImportBlocks() { applyDAOHardFork(vmdb) } - for _, tx := range block.Transactions() { - + for i, tx := range block.Transactions() { receipt, gas, err := applyTransaction( - ctx, chainConfig, chainContext, nil, gp, suite.app.EvmKeeper, vmdb, header, tx, usedGas, vmConfig, + ctx, chainConfig, chainContext, nil, gp, suite.app.EvmKeeper, vmdb, header, tx, usedGas, vmConfig, i, ) suite.Require().NoError(err, "failed to apply tx at block %d; tx: %X; gas %d; receipt:%v", block.NumberU64(), tx.Hash(), gas, receipt) suite.Require().NotNil(receipt) @@ -230,7 +229,7 @@ func applyDAOHardFork(vmdb ethvm.StateDB) { func applyTransaction( ctx sdk.Context, config *ethparams.ChainConfig, bc ethcore.ChainContext, author *common.Address, gp *ethcore.GasPool, evmKeeper *evmkeeper.Keeper, vmdb *statedb.StateDB, header *ethtypes.Header, - tx *ethtypes.Transaction, usedGas *uint64, cfg ethvm.Config, + tx *ethtypes.Transaction, usedGas *uint64, cfg ethvm.Config, txIndex int, ) (*ethtypes.Receipt, uint64, error) { msg, err := ethcore.TransactionToMessage(tx, ethtypes.MakeSigner(config, header.Number), sdkmath.ZeroInt().BigInt()) if err != nil { @@ -271,7 +270,7 @@ func applyTransaction( receipt.Bloom = ethtypes.CreateBloom(ethtypes.Receipts{receipt}) receipt.BlockHash = header.Hash() receipt.BlockNumber = header.Number - receipt.TransactionIndex = uint(evmKeeper.GetTxIndexTransient(ctx)) + receipt.TransactionIndex = txIndex return receipt, execResult.UsedGas, err } diff --git a/x/evm/keeper/abci.go b/x/evm/keeper/abci.go index 6d1e3acd38..eb988ac17e 100644 --- a/x/evm/keeper/abci.go +++ b/x/evm/keeper/abci.go @@ -16,11 +16,7 @@ package keeper import ( - "cosmossdk.io/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - - ethtypes "github.com/ethereum/go-ethereum/core/types" ) // BeginBlock sets the sdk Context and EIP155 chain id to the Keeper. @@ -33,11 +29,9 @@ func (k *Keeper) BeginBlock(ctx sdk.Context) error { // KVStore. The EVM end block logic doesn't update the validator set, thus it returns // an empty slice. func (k *Keeper) EndBlock(ctx sdk.Context) error { - // Gas costs are handled within msg handler so costs should be ignored - infCtx := ctx.WithGasMeter(types.NewInfiniteGasMeter()) - - bloom := ethtypes.BytesToBloom(k.GetBlockBloomTransient(infCtx).Bytes()) - k.EmitBlockBloomEvent(infCtx, bloom) - + k.CollectTxBloom(ctx) + if err := k.CollectTxFee(ctx); err != nil { + return err + } return nil } diff --git a/x/evm/keeper/bloom.go b/x/evm/keeper/bloom.go new file mode 100644 index 0000000000..3e12542085 --- /dev/null +++ b/x/evm/keeper/bloom.go @@ -0,0 +1,36 @@ +package keeper + +import ( + "encoding/binary" + "math/big" + + "cosmossdk.io/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/evmos/ethermint/x/evm/types" +) + +func MsgKey(ctx sdk.Context) []byte { + var buf [16]byte + binary.BigEndian.PutUint64(buf[:8], uint64(ctx.TxIndex())) + binary.BigEndian.PutUint64(buf[8:], uint64(ctx.MsgIndex())) + return buf[:] +} + +func (k Keeper) SetTxBloom(ctx sdk.Context, bloom []byte) { + key := append(types.KeyPrefixTransientBloom, MsgKey(ctx)...) + store := ctx.KVStore(k.transientKey) + store.Set(key, bloom) +} + +func (k Keeper) CollectTxBloom(ctx sdk.Context) { + store := prefix.NewStore(ctx.KVStore(k.transientKey), types.KeyPrefixTransientBloom) + it := store.Iterator(nil, nil) + defer it.Close() + + bloom := new(big.Int) + for ; it.Valid(); it.Next() { + bloom.Or(bloom, big.NewInt(0).SetBytes(it.Value())) + } + + k.EmitBlockBloomEvent(ctx, bloom.Bytes()) +} diff --git a/x/evm/keeper/config.go b/x/evm/keeper/config.go index 068501fce5..1755eee828 100644 --- a/x/evm/keeper/config.go +++ b/x/evm/keeper/config.go @@ -76,8 +76,7 @@ func (k *Keeper) TxConfig(ctx sdk.Context, txHash common.Hash) statedb.TxConfig return statedb.NewTxConfig( common.BytesToHash(ctx.HeaderHash()), // BlockHash txHash, // TxHash - uint(k.GetTxIndexTransient(ctx)), // TxIndex - uint(k.GetLogSizeTransient(ctx)), // LogIndex + 0, 0, ) } diff --git a/x/evm/keeper/gas.go b/x/evm/keeper/gas.go index 0e802205dc..c881450731 100644 --- a/x/evm/keeper/gas.go +++ b/x/evm/keeper/gas.go @@ -16,6 +16,7 @@ package keeper import ( + "fmt" "math/big" "github.com/ethereum/go-ethereum/core" @@ -30,6 +31,19 @@ import ( "github.com/evmos/ethermint/x/evm/types" ) +func tempFeeCollectorName(i int) string { + return fmt.Sprintf("%s%d", authtypes.TempFeeCollectorPrefix, i) +} + +// in finalize block context, we collect the fee to a temporary account first, +// which is to be moved to the real fee collector at the end of the block. +func feeCollectorName(ctx sdk.Context) string { + if ctx.TxIndex() >= 0 { + return tempFeeCollectorName(ctx.TxIndex()) + } + return authtypes.FeeCollectorName +} + // GetEthIntrinsicGas returns the intrinsic gas cost for the transaction func (k *Keeper) GetEthIntrinsicGas(ctx sdk.Context, msg core.Message, cfg *params.ChainConfig, isContractCreation bool) (uint64, error) { height := big.NewInt(ctx.BlockHeight()) @@ -57,8 +71,7 @@ func (k *Keeper) RefundGas(ctx sdk.Context, msg core.Message, leftoverGas uint64 refundedCoins := sdk.Coins{sdk.NewCoin(denom, sdkmath.NewIntFromBigInt(remaining))} // refund to sender from the fee collector module account, which is the escrow account in charge of collecting tx fees - - err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, authtypes.FeeCollectorName, msg.From.Bytes(), refundedCoins) + err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, feeCollectorName(ctx), msg.From.Bytes(), refundedCoins) if err != nil { err = errorsmod.Wrapf(errortypes.ErrInsufficientFunds, "fee collector account failed to refund fees: %s", err.Error()) return errorsmod.Wrapf(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String()) @@ -89,3 +102,30 @@ func GasToRefund(availableRefund, gasConsumed, refundQuotient uint64) uint64 { } return refund } + +// DeductFees deducts fees from the given account. +func DeductFees(bankKeeper authtypes.BankKeeper, ctx sdk.Context, acc sdk.AccountI, fees sdk.Coins) error { + if !fees.IsValid() { + return errorsmod.Wrapf(errortypes.ErrInsufficientFee, "invalid fee amount: %s", fees) + } + + if err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), feeCollectorName(ctx), fees); err != nil { + return errorsmod.Wrapf(errortypes.ErrInsufficientFunds, err.Error()) + } + + return nil +} + +func (k *Keeper) CollectTxFee(ctx sdk.Context) error { + for i := 0; i < ctx.TxCount(); i++ { + tempFeeCollector := tempFeeCollectorName(ctx.TxIndex()) + fees := k.bankKeeper.GetAllBalances(ctx, k.accountKeeper.GetModuleAddress(tempFeeCollector)) + if !fees.IsZero() { + if err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, tempFeeCollector, authtypes.FeeCollectorName, fees); err != nil { + return err + } + } + } + + return nil +} diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index b696d6aab6..1a9cdaea13 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -22,7 +22,6 @@ import ( errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" sdkmath "cosmossdk.io/math" - "cosmossdk.io/store/prefix" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -157,11 +156,11 @@ func (k Keeper) ChainID() *big.Int { // ---------------------------------------------------------------------------- // EmitBlockBloomEvent emit block bloom events -func (k Keeper) EmitBlockBloomEvent(ctx sdk.Context, bloom ethtypes.Bloom) { +func (k Keeper) EmitBlockBloomEvent(ctx sdk.Context, bloom []byte) { ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeBlockBloom, - sdk.NewAttribute(types.AttributeKeyEthereumBloom, string(bloom.Bytes())), + sdk.NewAttribute(types.AttributeKeyEthereumBloom, string(bloom)), ), ) } @@ -171,69 +170,6 @@ func (k Keeper) GetAuthority() sdk.AccAddress { return k.authority } -// GetBlockBloomTransient returns bloom bytes for the current block height -func (k Keeper) GetBlockBloomTransient(ctx sdk.Context) *big.Int { - store := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientBloom) - heightBz := sdk.Uint64ToBigEndian(uint64(ctx.BlockHeight())) - bz := store.Get(heightBz) - if len(bz) == 0 { - return big.NewInt(0) - } - - return new(big.Int).SetBytes(bz) -} - -// SetBlockBloomTransient sets the given bloom bytes to the transient store. This value is reset on -// every block. -func (k Keeper) SetBlockBloomTransient(ctx sdk.Context, bloom *big.Int) { - store := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientBloom) - heightBz := sdk.Uint64ToBigEndian(uint64(ctx.BlockHeight())) - store.Set(heightBz, bloom.Bytes()) -} - -// ---------------------------------------------------------------------------- -// Tx -// ---------------------------------------------------------------------------- - -// SetTxIndexTransient set the index of processing transaction -func (k Keeper) SetTxIndexTransient(ctx sdk.Context, index uint64) { - store := ctx.TransientStore(k.transientKey) - store.Set(types.KeyPrefixTransientTxIndex, sdk.Uint64ToBigEndian(index)) -} - -// GetTxIndexTransient returns EVM transaction index on the current block. -func (k Keeper) GetTxIndexTransient(ctx sdk.Context) uint64 { - store := ctx.TransientStore(k.transientKey) - bz := store.Get(types.KeyPrefixTransientTxIndex) - if len(bz) == 0 { - return 0 - } - - return sdk.BigEndianToUint64(bz) -} - -// ---------------------------------------------------------------------------- -// Log -// ---------------------------------------------------------------------------- - -// GetLogSizeTransient returns EVM log index on the current block. -func (k Keeper) GetLogSizeTransient(ctx sdk.Context) uint64 { - store := ctx.TransientStore(k.transientKey) - bz := store.Get(types.KeyPrefixTransientLogSize) - if len(bz) == 0 { - return 0 - } - - return sdk.BigEndianToUint64(bz) -} - -// SetLogSizeTransient fetches the current EVM log index from the transient store, increases its -// value by one and then sets the new index back to the transient store. -func (k Keeper) SetLogSizeTransient(ctx sdk.Context, logSize uint64) { - store := ctx.TransientStore(k.transientKey) - store.Set(types.KeyPrefixTransientLogSize, sdk.Uint64ToBigEndian(logSize)) -} - // ---------------------------------------------------------------------------- // Storage // ---------------------------------------------------------------------------- @@ -370,16 +306,11 @@ func (k Keeper) GetMinGasMultiplier(ctx sdk.Context) sdkmath.LegacyDec { return fmkParmas.MinGasMultiplier } -// ResetTransientGasUsed reset gas used to prepare for execution of current cosmos tx, called in ante handler. -func (k Keeper) ResetTransientGasUsed(ctx sdk.Context) { - store := ctx.TransientStore(k.transientKey) - store.Delete(types.KeyPrefixTransientGasUsed) -} - // GetTransientGasUsed returns the gas used by current cosmos tx. func (k Keeper) GetTransientGasUsed(ctx sdk.Context) uint64 { store := ctx.TransientStore(k.transientKey) - bz := store.Get(types.KeyPrefixTransientGasUsed) + key := append(types.KeyPrefixTransientGasUsed, sdk.Uint64ToBigEndian(uint64(ctx.TxIndex()))...) + bz := store.Get(key) if len(bz) == 0 { return 0 } @@ -389,8 +320,8 @@ func (k Keeper) GetTransientGasUsed(ctx sdk.Context) uint64 { // SetTransientGasUsed sets the gas used by current cosmos tx. func (k Keeper) SetTransientGasUsed(ctx sdk.Context, gasUsed uint64) { store := ctx.TransientStore(k.transientKey) - bz := sdk.Uint64ToBigEndian(gasUsed) - store.Set(types.KeyPrefixTransientGasUsed, bz) + key := append(types.KeyPrefixTransientGasUsed, sdk.Uint64ToBigEndian(uint64(ctx.TxIndex()))...) + store.Set(key, sdk.Uint64ToBigEndian(gasUsed)) } // AddTransientGasUsed accumulate gas used by each eth msgs included in current cosmos tx. diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 8c954bbd51..cb23aad6fc 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -44,7 +44,6 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t ctx := sdk.UnwrapSDKContext(goCtx) tx := msg.AsTransaction() - txIndex := k.GetTxIndexTransient(ctx) labels := []metrics.Label{ telemetry.NewLabel("tx_type", fmt.Sprintf("%d", tx.Type())), @@ -92,8 +91,6 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t sdk.NewAttribute(sdk.AttributeKeyAmount, tx.Value().String()), // add event for ethereum transaction hash format sdk.NewAttribute(types.AttributeKeyEthereumTxHash, response.Hash), - // add event for index of valid ethereum tx - sdk.NewAttribute(types.AttributeKeyTxIndex, strconv.FormatUint(txIndex, 10)), // add event for eth tx gas used, we can't get it from cosmos tx result when it contains multiple eth tx msgs. sdk.NewAttribute(types.AttributeKeyTxGasUsed, strconv.FormatUint(response.GasUsed, 10)), } diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index 4288dc8fd2..583b112f19 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -167,11 +167,6 @@ func (k Keeper) GetHashFn(ctx sdk.Context) vm.GetHashFunc { // // For relevant discussion see: https://github.com/cosmos/cosmos-sdk/discussions/9072 func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) (*types.MsgEthereumTxResponse, error) { - var ( - bloom *big.Int - bloomReceipt ethtypes.Bloom - ) - ethTx := msgEth.AsTransaction() cfg, err := k.EVMConfig(ctx, sdk.ConsAddress(ctx.BlockHeader().ProposerAddress), k.eip155ChainID, ethTx.Hash()) if err != nil { @@ -204,9 +199,7 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) // Compute block bloom filter if len(logs) > 0 { - bloom = k.GetBlockBloomTransient(ctx) - bloom.Or(bloom, big.NewInt(0).SetBytes(ethtypes.LogsBloom(logs))) - bloomReceipt = ethtypes.BytesToBloom(bloom.Bytes()) + k.SetTxBloom(tmpCtx, ethtypes.LogsBloom(logs)) } cumulativeGasUsed := res.GasUsed @@ -227,14 +220,12 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) Type: ethTx.Type(), PostState: nil, // TODO: intermediate state root CumulativeGasUsed: cumulativeGasUsed, - Bloom: bloomReceipt, Logs: logs, TxHash: cfg.TxConfig.TxHash, ContractAddress: contractAddr, GasUsed: res.GasUsed, BlockHash: cfg.TxConfig.BlockHash, BlockNumber: big.NewInt(ctx.BlockHeight()), - TransactionIndex: cfg.TxConfig.TxIndex, } if !res.Failed() { @@ -257,17 +248,9 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) // refund gas in order to match the Ethereum gas consumption instead of the default SDK one. if err = k.RefundGas(ctx, msg, msg.GasLimit-res.GasUsed, cfg.Params.EvmDenom); err != nil { - return nil, errorsmod.Wrapf(err, "failed to refund gas leftover gas to sender %s", msg.From) + return nil, errorsmod.Wrapf(err, "failed to refund leftover gas to sender %s", msg.From) } - if len(receipt.Logs) > 0 { - // Update transient block bloom filter - k.SetBlockBloomTransient(ctx, receipt.Bloom.Big()) - k.SetLogSizeTransient(ctx, uint64(cfg.TxConfig.LogIndex)+uint64(len(receipt.Logs))) - } - - k.SetTxIndexTransient(ctx, uint64(cfg.TxConfig.TxIndex)+1) - totalGasUsed, err := k.AddTransientGasUsed(ctx, res.GasUsed) if err != nil { return nil, errorsmod.Wrap(err, "failed to add transient gas used") diff --git a/x/evm/keeper/utils.go b/x/evm/keeper/utils.go index 2039ee4175..e9d3ab0017 100644 --- a/x/evm/keeper/utils.go +++ b/x/evm/keeper/utils.go @@ -27,7 +27,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" authante "github.com/cosmos/cosmos-sdk/x/auth/ante" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/evmos/ethermint/x/evm/types" @@ -159,17 +158,3 @@ func CheckSenderBalance( } return nil } - -// DeductFees deducts fees from the given account. -func DeductFees(bankKeeper authtypes.BankKeeper, ctx sdk.Context, acc sdk.AccountI, fees sdk.Coins) error { - if !fees.IsValid() { - return errorsmod.Wrapf(errortypes.ErrInsufficientFee, "invalid fee amount: %s", fees) - } - - err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), authtypes.FeeCollectorName, fees) - if err != nil { - return errorsmod.Wrapf(errortypes.ErrInsufficientFunds, err.Error()) - } - - return nil -} diff --git a/x/evm/types/interfaces.go b/x/evm/types/interfaces.go index 4081471129..76f08b0f37 100644 --- a/x/evm/types/interfaces.go +++ b/x/evm/types/interfaces.go @@ -46,7 +46,9 @@ type AccountKeeper interface { type BankKeeper interface { authtypes.BankKeeper GetBalance(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin + GetAllBalances(ctx context.Context, addr sdk.AccAddress) sdk.Coins SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromModuleToModule(ctx context.Context, senderModule, recipientModule string, amt sdk.Coins) error MintCoins(ctx context.Context, moduleName string, amt sdk.Coins) error BurnCoins(ctx context.Context, moduleName string, amt sdk.Coins) error BlockedAddr(addr sdk.AccAddress) bool diff --git a/x/evm/types/key.go b/x/evm/types/key.go index f8d768fc85..589495d3f3 100644 --- a/x/evm/types/key.go +++ b/x/evm/types/key.go @@ -46,8 +46,6 @@ const ( // prefix bytes for the EVM transient store const ( prefixTransientBloom = iota + 1 - prefixTransientTxIndex - prefixTransientLogSize prefixTransientGasUsed ) @@ -61,8 +59,6 @@ var ( // Transient Store key prefixes var ( KeyPrefixTransientBloom = []byte{prefixTransientBloom} - KeyPrefixTransientTxIndex = []byte{prefixTransientTxIndex} - KeyPrefixTransientLogSize = []byte{prefixTransientLogSize} KeyPrefixTransientGasUsed = []byte{prefixTransientGasUsed} ) diff --git a/x/evm/types/response.go b/x/evm/types/response.go new file mode 100644 index 0000000000..9409f82d1c --- /dev/null +++ b/x/evm/types/response.go @@ -0,0 +1,65 @@ +package types + +import ( + "strconv" + + abci "github.com/cometbft/cometbft/abci/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + proto "github.com/cosmos/gogoproto/proto" +) + +// PatchTxResponses fills the evm tx index and log indexes in the tx result +func PatchTxResponses(input []*abci.ExecTxResult) []*abci.ExecTxResult { + var ( + txIndex uint64 + logIndex uint64 + ) + for _, res := range input { + // assume no error result in msg handler + if res.Code != 0 { + continue + } + + var txMsgData sdk.TxMsgData + if err := proto.Unmarshal(res.Data, &txMsgData); err != nil { + continue + } + + var dirty bool + for i, rsp := range txMsgData.MsgResponses { + var response MsgEthereumTxResponse + if rsp.TypeUrl != "/"+proto.MessageName(&response) { + continue + } + if err := proto.Unmarshal(rsp.Value, &response); err != nil { + continue + } + + res.Events = append(res.Events, abci.Event(sdk.NewEvent( + EventTypeEthereumTx, + sdk.NewAttribute(AttributeKeyTxIndex, strconv.FormatUint(txIndex, 10)), + ))) + for _, log := range response.Logs { + log.TxIndex = txIndex + log.Index = logIndex + logIndex++ + } + txIndex++ + + dirty = true + any, err := codectypes.NewAnyWithValue(&response) + if err != nil { + panic(err) + } + txMsgData.MsgResponses[i] = any + } + + if dirty { + if data, err := proto.Marshal(&txMsgData); err != nil { + res.Data = data + } + } + } + return input +} diff --git a/x/evm/types/utils_test.go b/x/evm/types/utils_test.go index 981c742cb5..4cc70aca18 100644 --- a/x/evm/types/utils_test.go +++ b/x/evm/types/utils_test.go @@ -40,11 +40,11 @@ func TestEvmDataEncoding(t *testing.T) { txDataBz, err := proto.Marshal(txData) require.NoError(t, err) - res, err := evmtypes.DecodeTxResponse(txDataBz) + rsps, err := evmtypes.DecodeTxResponses(txDataBz) require.NoError(t, err) - require.NotNil(t, res) - require.Equal(t, data.Logs, res.Logs) - require.Equal(t, ret, res.Ret) + require.NotEmpty(t, rsps) + require.Equal(t, data.Logs, rsps[0].Logs) + require.Equal(t, ret, rsps[0].Ret) } func TestUnwrapEthererumMsg(t *testing.T) {