Skip to content

Commit

Permalink
Merge pull request #161 from stratosnet/Tx_Override
Browse files Browse the repository at this point in the history
Feat/QB1252: Evm tx override
  • Loading branch information
alexstratos authored Aug 8, 2022
2 parents bca3fe3 + d580778 commit 39653f1
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 29 deletions.
39 changes: 39 additions & 0 deletions app/ante/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,9 @@ func NewEthIncrementSenderSequenceDecorator(ak evmtypes.AccountKeeper) EthIncrem
// contract creation, the nonce will be incremented during the transaction execution and not within
// this AnteHandler decorator.
func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
if ctx.IsCheckTx() {
return next(ctx, tx, simulate)
}
for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
Expand Down Expand Up @@ -536,3 +539,39 @@ func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulat

return next(ctx, tx, simulate)
}

type EthTxOverrideDecorator struct {
evmKeeper EVMKeeper
}

// NewEthTxOverrideDecorator creates a new EthTxOverrideDecorator
func NewEthTxOverrideDecorator(ek EVMKeeper) EthTxOverrideDecorator {
return EthTxOverrideDecorator{
evmKeeper: ek,
}
}

func (tod EthTxOverrideDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
if ctx.IsCheckTx() {
return next(ctx, tx, simulate)
}

overriddenTxs := tod.evmKeeper.GetOverriddenTxHashMap(ctx)
if len(overriddenTxs) == 0 {
return next(ctx, tx, simulate)
}

for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}

_, ok = overriddenTxs[msgEthTx.Hash]
if ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrWrongSequence, "transaction is overridden")
}
}

return next(ctx, tx, simulate)
}
3 changes: 2 additions & 1 deletion app/ante/handler_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ func (options HandlerOptions) Validate() error {
func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler {
return sdk.ChainAnteDecorators(
NewEthSetUpContextDecorator(options.EvmKeeper), // outermost AnteDecorator. SetUpContext must be called first
NewEthMempoolFeeDecorator(options.EvmKeeper), // Check eth effective gas price against minimal-gas-prices
NewEthTxOverrideDecorator(options.EvmKeeper),
NewEthMempoolFeeDecorator(options.EvmKeeper), // Check eth effective gas price against minimal-gas-prices
NewEthValidateBasicDecorator(options.EvmKeeper),
NewEthSigVerificationDecorator(options.EvmKeeper),
NewEthAccountVerificationDecorator(options.AccountKeeper, options.EvmKeeper),
Expand Down
2 changes: 1 addition & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ func NewInitApp(
app.evmKeeper = evmkeeper.NewKeeper(
appCodec, keys[evmtypes.StoreKey], tKeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName),
app.accountKeeper, app.bankKeeper, app.stakingKeeper,
tracer,
tracer, encodingConfig.TxConfig.TxDecoder(),
)

// Create IBC Keeper
Expand Down
16 changes: 11 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ module github.com/stratosnet/stratos-chain

go 1.17

replace google.golang.org/grpc => google.golang.org/grpc v1.33.2


require (
github.com/btcsuite/btcd v0.22.1
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce
Expand All @@ -26,7 +23,9 @@ require (
github.com/rs/cors v1.8.2
github.com/spf13/cast v1.4.1
github.com/spf13/cobra v1.4.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.11.0
github.com/stretchr/testify v1.7.1
github.com/tendermint/tendermint v0.34.19
github.com/tendermint/tm-db v0.6.7
github.com/tyler-smith/go-bip39 v1.1.0
Expand Down Expand Up @@ -100,16 +99,25 @@ require (
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/klauspost/cpuid/v2 v2.0.4 // indirect
github.com/lib/pq v1.10.4 // indirect
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
github.com/minio/highwayhash v1.0.2 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/multiformats/go-base32 v0.0.3 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/multiformats/go-multibase v0.0.3 // indirect
github.com/multiformats/go-multihash v0.0.15 // indirect
github.com/multiformats/go-varint v0.0.6 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
Expand All @@ -128,9 +136,7 @@ require (
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 // indirect
github.com/stretchr/testify v1.7.1 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/tendermint/btcd v0.1.1 // indirect
Expand Down
25 changes: 10 additions & 15 deletions rpc/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,15 @@ const (
)

// APICreator creates the JSON-RPC API implementations.
type APICreator = func(*server.Context, client.Context, *rpcclient.WSClient, string) []rpc.API
type APICreator = func(*server.Context, client.Context, *rpcclient.WSClient) []rpc.API

// apiCreators defines the JSON-RPC API namespaces.
var apiCreators map[string]APICreator

func init() {
apiCreators = map[string]APICreator{
EthNamespace: func(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient, evmChainId string) []rpc.API {
EthNamespace: func(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient) []rpc.API {
nonceLock := new(types.AddrLocker)
clientCtx = clientCtx.WithChainID(evmChainId)
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx)
return []rpc.API{
{
Expand All @@ -70,7 +69,7 @@ func init() {
},
}
},
Web3Namespace: func(*server.Context, client.Context, *rpcclient.WSClient, string) []rpc.API {
Web3Namespace: func(*server.Context, client.Context, *rpcclient.WSClient) []rpc.API {
return []rpc.API{
{
Namespace: Web3Namespace,
Expand All @@ -80,8 +79,7 @@ func init() {
},
}
},
NetNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient, evmChainId string) []rpc.API {
clientCtx = clientCtx.WithChainID(evmChainId)
NetNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
return []rpc.API{
{
Namespace: NetNamespace,
Expand All @@ -91,8 +89,7 @@ func init() {
},
}
},
PersonalNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient, evmChainId string) []rpc.API {
clientCtx = clientCtx.WithChainID(evmChainId)
PersonalNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx)
return []rpc.API{
{
Expand All @@ -103,7 +100,7 @@ func init() {
},
}
},
TxPoolNamespace: func(ctx *server.Context, _ client.Context, _ *rpcclient.WSClient, evmChainId string) []rpc.API {
TxPoolNamespace: func(ctx *server.Context, _ client.Context, _ *rpcclient.WSClient) []rpc.API {
return []rpc.API{
{
Namespace: TxPoolNamespace,
Expand All @@ -113,8 +110,7 @@ func init() {
},
}
},
DebugNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient, evmChainId string) []rpc.API {
clientCtx = clientCtx.WithChainID(evmChainId)
DebugNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx)
return []rpc.API{
{
Expand All @@ -125,8 +121,7 @@ func init() {
},
}
},
MinerNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient, evmChainId string) []rpc.API {
clientCtx = clientCtx.WithChainID(evmChainId)
MinerNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx)
return []rpc.API{
{
Expand All @@ -141,12 +136,12 @@ func init() {
}

// GetRPCAPIs returns the list of all APIs
func GetRPCAPIs(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient, selectedAPIs []string, evmChainId string) []rpc.API {
func GetRPCAPIs(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient, selectedAPIs []string) []rpc.API {
var apis []rpc.API

for _, ns := range selectedAPIs {
if creator, ok := apiCreators[ns]; ok {
apis = append(apis, creator(ctx, clientCtx, tmWSClient, evmChainId)...)
apis = append(apis, creator(ctx, clientCtx, tmWSClient)...)
} else {
ctx.Logger.Error("invalid namespace value", "namespace", ns)
}
Expand Down
4 changes: 2 additions & 2 deletions server/json_rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
)

// StartJSONRPC starts the JSON-RPC server
func StartJSONRPC(ctx *server.Context, clientCtx client.Context, tmRPCAddr, tmEndpoint string, config config.Config, evmChainId string) (*http.Server, chan struct{}, error) {
func StartJSONRPC(ctx *server.Context, clientCtx client.Context, tmRPCAddr, tmEndpoint string, config config.Config) (*http.Server, chan struct{}, error) {
tmWsClient := ConnectTmWS(tmRPCAddr, tmEndpoint, ctx.Logger)

logger := ctx.Logger.With("module", "geth")
Expand All @@ -37,7 +37,7 @@ func StartJSONRPC(ctx *server.Context, clientCtx client.Context, tmRPCAddr, tmEn
rpcServer := ethrpc.NewServer()

rpcAPIArr := config.JSONRPC.API
apis := rpc.GetRPCAPIs(ctx, clientCtx, tmWsClient, rpcAPIArr, evmChainId)
apis := rpc.GetRPCAPIs(ctx, clientCtx, tmWsClient, rpcAPIArr)

for _, api := range apis {
if err := rpcServer.RegisterName(api.Namespace, api.Service); err != nil {
Expand Down
4 changes: 3 additions & 1 deletion server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,9 +426,11 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
genEvmParamsChainCfg := genEvmParams["chain_config"].(map[string]interface{})
genEvmParamsChainId := genEvmParamsChainCfg["chain_id"].(string)

clientCtx := clientCtx.WithChainID(genEvmParamsChainId)

tmEndpoint := "/websocket"
tmRPCAddr := cfg.RPC.ListenAddress
httpSrv, httpSrvDone, err = StartJSONRPC(ctx, clientCtx, tmRPCAddr, tmEndpoint, config, genEvmParamsChainId)
httpSrv, httpSrvDone, err = StartJSONRPC(ctx, clientCtx, tmRPCAddr, tmEndpoint, config)
if err != nil {
return err
}
Expand Down
79 changes: 76 additions & 3 deletions x/evm/keeper/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@ package keeper
import (
"fmt"

"github.com/stratosnet/stratos-chain/x/evm/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/rpc/core"
rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types"

sdk "github.com/cosmos/cosmos-sdk/types"

ethtypes "github.com/ethereum/go-ethereum/core/types"

"github.com/stratosnet/stratos-chain/x/evm/types"
)

var (
overriddenTxHashes map[string]struct{}
)

// BeginBlock sets the sdk Context and EIP155 chain id to the Keeper.
Expand All @@ -22,6 +28,66 @@ func (k *Keeper) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {

k.SetBaseFeeParam(ctx, baseFee)

if !ctx.IsCheckTx() {
overriddenTxHashes = make(map[string]struct{}, 0)
block, err := core.BlockByHash(&rpctypes.Context{}, ctx.HeaderHash().Bytes())
rawTxs := block.Block.Txs
if err != nil {
panic(err)
}

for _, rawTx := range rawTxs {
tx, err := k.txDecoder(rawTx)
if err != nil {
panic(err)
}

for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*types.MsgEthereumTx)
if !ok {
continue
}

txData, err := types.UnpackTxData(msgEthTx.Data)
if err != nil {
panic(err)
}

from := msgEthTx.GetFrom()
nonce := txData.GetNonce()
gasPrice := txData.GetGasPrice()

for _, rawTx2 := range rawTxs {
tx2, err := k.txDecoder(rawTx2)
if err != nil {
continue
}

for _, msg2 := range tx2.GetMsgs() {
msgEthTx2, ok := msg2.(*types.MsgEthereumTx)
if !ok {
continue
}

txData2, err := types.UnpackTxData(msgEthTx2.Data)
if err != nil {
panic(err)
}

if from.Equals(msgEthTx2.GetFrom()) && nonce == txData2.GetNonce() && gasPrice.Cmp(txData2.GetGasPrice()) < 0 {
// find tx has same nonce with higher gas price from same sender,
// record tx hash to overriddenTxHashes, let it fail in anteHandler
// overriddenTxHashes need to be cleared in the EndBlock function
overriddenTxHashes[msgEthTx.Hash] = struct{}{}
break
}
}
}

}
}
}

// Store current base fee in event
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
Expand All @@ -39,7 +105,7 @@ func (k *Keeper) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.Vali
k.Logger(ctx).Error("block gas meter is nil when setting block gas used")
panic("block gas meter is nil when setting block gas used")
}

overriddenTxHashes = nil
gasUsed := ctx.BlockGasMeter().GasConsumedToLimit()

k.SetBlockGasUsed(ctx, gasUsed)
Expand All @@ -58,3 +124,10 @@ func (k *Keeper) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.Vali

return []abci.ValidatorUpdate{}
}

func (k *Keeper) GetOverriddenTxHashMap(ctx sdk.Context) map[string]struct{} {
if ctx.IsCheckTx() {
return nil
}
return overriddenTxHashes
}
4 changes: 3 additions & 1 deletion x/evm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type Keeper struct {
// Tracer used to collect execution traces from the EVM transaction execution
tracer string

txDecoder sdk.TxDecoder
// EVM Hooks for tx post-processing
hooks types.EvmHooks
}
Expand All @@ -57,7 +58,7 @@ func NewKeeper(
cdc codec.BinaryCodec,
storeKey, transientKey sdk.StoreKey, paramSpace paramtypes.Subspace,
ak types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper,
tracer string,
tracer string, txDecoder sdk.TxDecoder,
) *Keeper {
// ensure evm module account is set
if addr := ak.GetModuleAddress(types.ModuleName); addr == nil {
Expand All @@ -79,6 +80,7 @@ func NewKeeper(
storeKey: storeKey,
transientKey: transientKey,
tracer: tracer,
txDecoder: txDecoder,
}
}

Expand Down
2 changes: 2 additions & 0 deletions x/evm/statedb/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ type Keeper interface {
GetAccount(ctx sdk.Context, addr common.Address) *Account
GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash
GetCode(ctx sdk.Context, codeHash common.Hash) []byte
GetOverriddenTxHashMap(ctx sdk.Context) map[string]struct{}

// the callback returns false to break early
ForEachStorage(ctx sdk.Context, addr common.Address, cb func(key, value common.Hash) bool)

Expand Down

0 comments on commit 39653f1

Please sign in to comment.