Skip to content

Commit

Permalink
block-stm integration
Browse files Browse the repository at this point in the history
- patch tx response to fix tx index and log index
- collect tx fee to temporary module account
  • Loading branch information
yihuang committed Mar 17, 2024
1 parent 41e81d6 commit af6bc09
Show file tree
Hide file tree
Showing 24 changed files with 418 additions and 220 deletions.
1 change: 0 additions & 1 deletion app/ante/handler_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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...)
Expand Down
2 changes: 0 additions & 2 deletions app/ante/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
38 changes: 0 additions & 38 deletions app/ante/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package ante
import (
"errors"
"math/big"
"strconv"

errorsmod "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
Expand Down Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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])

Expand Down Expand Up @@ -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)
}

Check warning

Code scanning / CodeQL

Iteration over map Warning

Iteration over map may be a possible source of non-determinism
for _, key := range app.tkeys {
keys = append(keys, key)
}

Check warning

Code scanning / CodeQL

Iteration over map Warning

Iteration over map may be a possible source of non-determinism
for _, key := range app.memKeys {
keys = append(keys, key)
}

Check warning

Code scanning / CodeQL

Iteration over map Warning

Iteration over map may be a possible source of non-determinism
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.
Expand Down
159 changes: 159 additions & 0 deletions app/executor.go
Original file line number Diff line number Diff line change
@@ -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))
}
16 changes: 9 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
)

Expand Down Expand Up @@ -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
Expand All @@ -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.20240317073512-765d243fd896
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
)
Loading

0 comments on commit af6bc09

Please sign in to comment.