update fork

This commit is contained in:
0xmuralik
2022-10-10 16:08:33 +05:30
parent 632d53e34a
commit 56d59feaa0
383 changed files with 36784 additions and 21462 deletions
-181
View File
@@ -1,181 +0,0 @@
# x/evm
The `x/evm` module is responsible for executing Ethereum Virtual Machine (EVM) state transitions.
## Usage
1. Import the module and the dependency packages.
```go
import (
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cerc-io/laconicd/app/ante"
ethermint "github.com/cerc-io/laconicd/types"
"github.com/cerc-io/laconicd/x/evm"
)
```
2. Add `AppModuleBasic` to your `ModuleBasics`.
```go
var (
ModuleBasics = module.NewBasicManager(
// ...
evm.AppModuleBasic{},
)
)
```
3. Create the module's parameter subspace in your application constructor.
```go
func NewApp(...) *App {
// ...
app.subspaces[evm.ModuleName] = app.ParamsKeeper.Subspace(evm.DefaultParamspace)
}
```
4. Define the Ethermint `ProtoAccount` for the `AccountKeeper`
```go
func NewApp(...) *App {
// ...
app.AccountKeeper = auth.NewAccountKeeper(
cdc, keys[auth.StoreKey], app.subspaces[auth.ModuleName], ethermint.ProtoAccount,
)
}
```
5. Create the keeper.
```go
func NewApp(...) *App {
// ...
app.EvmKeeper = evm.NewKeeper(
app.cdc, keys[evm.StoreKey], app.subspaces[evm.ModuleName], app.AccountKeeper,
)
}
```
6. Add the `x/evm` module to the app's `ModuleManager`.
```go
func NewApp(...) *App {
// ...
app.mm = module.NewManager(
// ...
evm.NewAppModule(app.EvmKeeper, app.AccountKeeper),
// ...
)
}
```
7. Set the `x/evm` module `BeginBlock` and `EndBlock` ordering:
```go
app.mm.SetOrderBeginBlockers(
evm.ModuleName, ...
)
app.mm.SetOrderEndBlockers(
evm.ModuleName, ...
)
```
8. Set the `x/evm` module genesis order. The module must go after the `auth` and `bank` modules.
```go
func NewApp(...) *App {
// ...
app.mm.SetOrderInitGenesis(auth.ModuleName, bank.ModuleName, ... , evm.ModuleName, ...)
}
```
9. Set the Ethermint `AnteHandler` to support EVM transactions. Note,
the default `AnteHandler` provided by the `x/evm` module depends on the `x/auth` and `x/supply`
modules.
```go
func NewApp(...) *App {
// ...
app.SetAnteHandler(ante.NewAnteHandler(
app.AccountKeeper, app.EvmKeeper, app.SupplyKeeper
))
}
```
## Genesis
The `x/evm` module defines its genesis state as follows:
```go
type GenesisState struct {
Accounts []GenesisAccount `json:"accounts"`
TxsLogs []TransactionLogs `json:"txs_logs"`
ChainConfig ChainConfig `json:"chain_config"`
Params Params `json:"params"`
}
```
Which relies on the following types:
```go
type GenesisAccount struct {
Address string `json:"address"`
Balance sdk.Int `json:"balance"`
Code hexutil.Bytes `json:"code,omitempty"`
Storage Storage `json:"storage,omitempty"`
}
type TransactionLogs struct {
Hash common.Hash `json:"hash"`
Logs []*ethtypes.Log `json:"logs"`
}
type ChainConfig struct {
HomesteadBlock sdk.Int `json:"homestead_block" yaml:"homestead_block"` // Homestead switch block (< 0 no fork, 0 = already homestead)
DAOForkBlock sdk.Int `json:"dao_fork_block" yaml:"dao_fork_block"` // TheDAO hard-fork switch block (< 0 no fork)
DAOForkSupport bool `json:"dao_fork_support" yaml:"dao_fork_support"` // Whether the nodes supports or opposes the DAO hard-fork
// EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
EIP150Block sdk.Int `json:"eip150_block" yaml:"eip150_block"` // EIP150 HF block (< 0 no fork)
EIP150Hash string `json:"eip150_hash" yaml:"eip150_hash"` // EIP150 HF hash (needed for header only clients as only gas pricing changed)
EIP155Block sdk.Int `json:"eip155_block" yaml:"eip155_block"` // EIP155 HF block
EIP158Block sdk.Int `json:"eip158_block" yaml:"eip158_block"` // EIP158 HF block
ByzantiumBlock sdk.Int `json:"byzantium_block" yaml:"byzantium_block"` // Byzantium switch block (< 0 no fork, 0 = already on byzantium)
ConstantinopleBlock sdk.Int `json:"constantinople_block" yaml:"constantinople_block"` // Constantinople switch block (< 0 no fork, 0 = already activated)
PetersburgBlock sdk.Int `json:"petersburg_block" yaml:"petersburg_block"` // Petersburg switch block (< 0 same as Constantinople)
IstanbulBlock sdk.Int `json:"istanbul_block" yaml:"istanbul_block"` // Istanbul switch block (< 0 no fork, 0 = already on istanbul)
MuirGlacierBlock sdk.Int `json:"muir_glacier_block" yaml:"muir_glacier_block"` // Eip-2384 (bomb delay) switch block (< 0 no fork, 0 = already activated)
YoloV2Block sdk.Int `json:"yoloV2_block" yaml:"yoloV2_block"` // YOLO v1: https://github.com/ethereum/EIPs/pull/2657 (Ephemeral testnet)
EWASMBlock sdk.Int `json:"ewasm_block" yaml:"ewasm_block"` // EWASM switch block (< 0 no fork, 0 = already activated)
}
type Params struct {
// EVMDenom defines the token denomination used for state transitions on the
// EVM module.
EvmDenom string `json:"evm_denom" yaml:"evm_denom"`
// EnableCreate toggles state transitions that use the vm.Create function
EnableCreate bool `json:"enable_create" yaml:"enable_create"`
// EnableCall toggles state transitions that use the vm.Call function
EnableCall bool `json:"enable_call" yaml:"enable_call"`
// ExtraEIPs defines the additional EIPs for the vm.Config
ExtraEIPs []int `json:"extra_eips" yaml:"extra_eips"`
}
```
## Client
### JSON-RPC
See the Ethermint [JSON-RPC docs](https://evmos.dev/basics/json_rpc.html) for reference.
## Documentation and Specification
- Ethermint documentation: [https://evmos.dev](https://evmos.dev)
-34
View File
@@ -1,34 +0,0 @@
[module]
description = "The evm module executes Ethereum Virtual Machine (EVM) state transitions."
homepage = "https://github.com/cerc-io/laconicd"
keywords = [
"evm",
"ethereum",
"ethermint",
]
name = "x/evm"
[bug_tracker]
url = "https://github.com/cerc-io/laconicd/issues"
[[authors]]
name = "fedekunze"
[[authors]]
name = "austinabell"
[[authors]]
name = "alexanderbez"
[[authors]]
name = "noot"
[[authors]]
name = "araskachoi"
[version]
documentation = "https://raw.githubusercontent.com/cerc-io/laconicd/main/x/evm/atlas/atlas-v0.3.1.md"
repo = "https://github.com/cerc-io/laconicd/releases/tag/v0.3.1"
sdk_compat = "v0.39.x"
version = "v0.3.1"
+31 -2
View File
@@ -1,7 +1,7 @@
package cli
import (
rpctypes "github.com/cerc-io/laconicd/rpc/ethereum/types"
rpctypes "github.com/cerc-io/laconicd/rpc/types"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
@@ -23,6 +23,7 @@ func GetQueryCmd() *cobra.Command {
cmd.AddCommand(
GetStorageCmd(),
GetCodeCmd(),
GetParamsCmd(),
)
return cmd
}
@@ -32,7 +33,7 @@ func GetStorageCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "storage [address] [key]",
Short: "Gets storage for an account with a given key and height",
Long: "Gets storage for an account with a given key and height. If the height is not provided, it will use the latest height from context.",
Long: "Gets storage for an account with a given key and height. If the height is not provided, it will use the latest height from context.", //nolint:lll
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
@@ -103,3 +104,31 @@ func GetCodeCmd() *cobra.Command {
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetParamsCmd queries the fee market params
func GetParamsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "params",
Short: "Get the evm params",
Long: "Get the evm parameter values.",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
+1 -1
View File
@@ -12,7 +12,7 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
rpctypes "github.com/cerc-io/laconicd/rpc/ethereum/types"
rpctypes "github.com/cerc-io/laconicd/rpc/types"
"github.com/cerc-io/laconicd/x/evm/types"
)
-98
View File
@@ -1,98 +0,0 @@
package rest
// clientrest "github.com/cosmos/cosmos-sdk/client/rest"
// "github.com/cosmos/cosmos-sdk/types/rest"
// authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
// // RegisterTxRoutes - Central function to define routes that get registered by the main application
// func RegisterTxRoutes(clientCtx client.Context, rtr *mux.Router) {
// r := testutil.GetRequestWithHeaders(rtr)
// r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(clientCtx)).Methods("GET")
// r.HandleFunc("/txs", testutil.QueryTxsRequestHandlerFn(clientCtx)).Methods("GET")
// r.HandleFunc("/txs/decode", testutil.DecodeTxRequestHandlerFn(clientCtx)).Methods("POST")
// }
// QueryTxRequestHandlerFn implements a REST handler that queries a transaction
// by hash in a committed block.
// func QueryTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
// return func(w http.ResponseWriter, r *http.Request) {
// vars := mux.Vars(r)
// hashHexStr := vars["hash"]
// clientCtx, ok := testutil.ParseQueryHeightOrReturnBadRequest(w, clientCtx, r)
// if !ok {
// return
// }
// ethHashPrefix := "0x"
// // if !strings.HasPrefix(hashHexStr, ethHashPrefix) {
// // authrest.QueryTxRequestHandlerFn(clientCtx)
// // return
// // }
// // eth Tx
// ethHashPrefixLength := len(ethHashPrefix)
// output, err := getEthTransactionByHash(clientCtx, hashHexStr[ethHashPrefixLength:])
// if err != nil {
// rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
// return
// }
// rest.PostProcessResponseBare(w, clientCtx, output)
// }
// }
// // GetTransactionByHash returns the transaction identified by hash.
// func getEthTransactionByHash(clientCtx client.Context, hashHex string) ([]byte, error) {
// hash, err := hex.DecodeString(hashHex)
// if err != nil {
// return nil, err
// }
// node, err := clientCtx.GetNode()
// if err != nil {
// return nil, err
// }
// tx, err := node.Tx(context.Background(), hash, false)
// if err != nil {
// return nil, err
// }
// // Can either cache or just leave this out if not necessary
// block, err := node.Block(context.Background(), &tx.Height)
// if err != nil {
// return nil, err
// }
// client := feemarkettypes.NewQueryClient(clientCtx)
// res, err := client.BaseFee(context.Background(), &feemarkettypes.QueryBaseFeeRequest{})
// if err != nil {
// return nil, err
// }
// var baseFee *big.Int
// if res.BaseFee != nil {
// baseFee = res.BaseFee.BigInt()
// }
// blockHash := common.BytesToHash(block.Block.Header.Hash())
// ethTxs, err := rpctypes.RawTxToEthTx(clientCtx, tx.Tx)
// if err != nil {
// return nil, err
// }
// height := uint64(tx.Height)
// for _, ethTx := range ethTxs {
// if common.HexToHash(ethTx.Hash) == common.BytesToHash(hash) {
// rpcTx, err := rpctypes.NewRPCTransaction(ethTx.AsTransaction(), blockHash, height, uint64(tx.Index), baseFee)
// if err != nil {
// return nil, err
// }
// return json.Marshal(rpcTx)
// }
// }
// return nil, errors.New("eth tx not found")
// }
+50 -25
View File
@@ -6,15 +6,20 @@ import (
"testing"
"time"
sdkmath "cosmossdk.io/math"
"github.com/gogo/protobuf/proto"
abci "github.com/tendermint/tendermint/abci/types"
tmjson "github.com/tendermint/tendermint/libs/json"
feemarkettypes "github.com/cerc-io/laconicd/x/feemarket/types"
"github.com/cosmos/cosmos-sdk/simapp"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/bank/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
@@ -57,7 +62,7 @@ type EvmTestSuite struct {
dynamicTxFee bool
}
/// DoSetupTest setup test environment, it uses`require.TestingT` to support both `testing.T` and `testing.B`.
// DoSetupTest setup test environment, it uses`require.TestingT` to support both `testing.T` and `testing.B`.
func (suite *EvmTestSuite) DoSetupTest(t require.TestingT) {
checkTx := false
@@ -72,7 +77,7 @@ func (suite *EvmTestSuite) DoSetupTest(t require.TestingT) {
require.NoError(t, err)
consAddress := sdk.ConsAddress(priv.PubKey().Address())
suite.app = app.Setup(suite.T(), checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
suite.app = app.Setup(checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
if suite.dynamicTxFee {
feemarketGenesis := feemarkettypes.DefaultGenesisState()
feemarketGenesis.Params.EnableHeight = 1
@@ -82,6 +87,39 @@ func (suite *EvmTestSuite) DoSetupTest(t require.TestingT) {
return genesis
})
coins := sdk.NewCoins(sdk.NewCoin(types.DefaultEVMDenom, sdkmath.NewInt(100000000000000)))
genesisState := app.NewTestGenesisState(suite.app.AppCodec())
b32address := sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), priv.PubKey().Address().Bytes())
balances := []banktypes.Balance{
{
Address: b32address,
Coins: coins,
},
{
Address: suite.app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName).String(),
Coins: coins,
},
}
var bankGenesis banktypes.GenesisState
suite.app.AppCodec().MustUnmarshalJSON(genesisState[banktypes.ModuleName], &bankGenesis)
// Update balances and total supply
bankGenesis.Balances = append(bankGenesis.Balances, balances...)
bankGenesis.Supply = bankGenesis.Supply.Add(coins...).Add(coins...)
genesisState[banktypes.ModuleName] = suite.app.AppCodec().MustMarshalJSON(&bankGenesis)
stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)
// Initialize the chain
suite.app.InitChain(
abci.RequestInitChain{
ChainId: "ethermint_9000-1",
Validators: []abci.ValidatorUpdate{},
ConsensusParams: app.DefaultConsensusParams,
AppStateBytes: stateBytes,
},
)
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{
Height: 1,
ChainID: "ethermint_9000-1",
@@ -106,25 +144,10 @@ func (suite *EvmTestSuite) DoSetupTest(t require.TestingT) {
LastResultsHash: tmhash.Sum([]byte("last_result")),
})
coins := sdk.NewCoins(sdk.NewCoin(types.DefaultEVMDenom, sdk.NewInt(100000000000000)))
b32address := sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), priv.PubKey().Address().Bytes())
accAddr, err := sdk.AccAddressFromBech32(b32address)
require.NoError(t, err)
acc := &ethermint.EthAccount{
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(accAddr.Bytes()), nil, 0, 0),
CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(),
}
err = testutil.FundAccount(suite.app.BankKeeper, suite.ctx, accAddr, coins)
require.NoError(t, err)
err = testutil.FundModuleAccount(suite.app.BankKeeper, suite.ctx, authtypes.FeeCollectorName, coins)
require.NoError(t, err)
queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, suite.app.EvmKeeper)
acc = &ethermint.EthAccount{
acc := &ethermint.EthAccount{
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(address.Bytes()), nil, 0, 0),
CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(),
}
@@ -546,13 +569,14 @@ func (suite *EvmTestSuite) TestERC20TransferReverted() {
k.SetHooks(tc.hooks)
// add some fund to pay gas fee
k.SetBalance(suite.ctx, suite.from, big.NewInt(10000000000))
k.SetBalance(suite.ctx, suite.from, big.NewInt(1000000000000000))
contract := suite.deployERC20Contract()
data, err := types.ERC20Contract.ABI.Pack("transfer", suite.from, big.NewInt(10))
suite.Require().NoError(err)
gasPrice := big.NewInt(1000000000) // must be bigger than or equal to baseFee
nonce := k.GetNonce(suite.ctx, suite.from)
tx := types.NewTx(
suite.chainID,
@@ -560,7 +584,7 @@ func (suite *EvmTestSuite) TestERC20TransferReverted() {
&contract,
big.NewInt(0),
tc.gasLimit,
big.NewInt(1),
gasPrice,
nil,
nil,
data,
@@ -572,7 +596,7 @@ func (suite *EvmTestSuite) TestERC20TransferReverted() {
txData, err := types.UnpackTxData(tx.Data)
suite.Require().NoError(err)
_, err = k.DeductTxCostsFromUserBalance(suite.ctx, *tx, txData, "aphoton", true, true, true)
_, _, err = k.DeductTxCostsFromUserBalance(suite.ctx, *tx, txData, "aphoton", true, true, true)
suite.Require().NoError(err)
res, err := k.EthereumTx(sdk.WrapSDKContext(suite.ctx), tx)
@@ -580,6 +604,7 @@ func (suite *EvmTestSuite) TestERC20TransferReverted() {
suite.Require().True(res.Failed())
suite.Require().Equal(tc.expErr, res.VmError)
suite.Require().Empty(res.Logs)
after := k.GetBalance(suite.ctx, suite.from)
@@ -590,7 +615,7 @@ func (suite *EvmTestSuite) TestERC20TransferReverted() {
}
// check gas refund works: only deducted fee for gas used, rather than gas limit.
suite.Require().Equal(big.NewInt(int64(res.GasUsed)), new(big.Int).Sub(before, after))
suite.Require().Equal(new(big.Int).Mul(gasPrice, big.NewInt(int64(res.GasUsed))), new(big.Int).Sub(before, after))
// nonce should not be increased.
nonce2 := k.GetNonce(suite.ctx, suite.from)
@@ -661,13 +686,13 @@ func (suite *EvmTestSuite) TestContractDeploymentRevert() {
// DummyHook implements EvmHooks interface
type DummyHook struct{}
func (dh *DummyHook) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
func (dh *DummyHook) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
return nil
}
// FailureHook implements EvmHooks interface
type FailureHook struct{}
func (dh *FailureHook) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
func (dh *FailureHook) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
return errors.New("mock error")
}
+9 -9
View File
@@ -4,21 +4,21 @@ import (
"math/big"
"testing"
"cosmossdk.io/math"
sdkmath "cosmossdk.io/math"
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/ethereum/go-ethereum/common"
ethermint "github.com/cerc-io/laconicd/types"
"github.com/cerc-io/laconicd/x/evm/types"
ante "github.com/cosmos/cosmos-sdk/x/auth/ante"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
func SetupContract(b *testing.B) (*KeeperTestSuite, common.Address) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
amt := sdk.Coins{ethermint.NewPhotonCoinInt64(1000000000000000000)}
err := suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, amt)
@@ -26,7 +26,7 @@ func SetupContract(b *testing.B) (*KeeperTestSuite, common.Address) {
err = suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, suite.address.Bytes(), amt)
require.NoError(b, err)
contractAddr := suite.DeployTestContract(b, suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(b, suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
return &suite, contractAddr
@@ -34,7 +34,7 @@ func SetupContract(b *testing.B) (*KeeperTestSuite, common.Address) {
func SetupTestMessageCall(b *testing.B) (*KeeperTestSuite, common.Address) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
amt := sdk.Coins{ethermint.NewPhotonCoinInt64(1000000000000000000)}
err := suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, amt)
@@ -67,8 +67,8 @@ func DoBenchmark(b *testing.B, txBuilder TxBuilder) {
txData, err := types.UnpackTxData(msg.Data)
require.NoError(b, err)
fees := sdk.Coins{sdk.NewCoin(suite.EvmDenom(), sdk.NewIntFromBigInt(txData.Fee()))}
err = ante.DeductFees(suite.app.BankKeeper, suite.ctx, suite.app.AccountKeeper.GetAccount(ctx, msg.GetFrom()), fees)
fees := sdk.Coins{sdk.NewCoin(suite.EvmDenom(), sdkmath.NewIntFromBigInt(txData.Fee()))}
err = authante.DeductFees(suite.app.BankKeeper, suite.ctx, suite.app.AccountKeeper.GetAccount(ctx, msg.GetFrom()), fees)
require.NoError(b, err)
rsp, err := suite.app.EvmKeeper.EthereumTx(sdk.WrapSDKContext(ctx), msg)
@@ -134,8 +134,8 @@ func BenchmarkMessageCall(b *testing.B) {
txData, err := types.UnpackTxData(msg.Data)
require.NoError(b, err)
fees := sdk.Coins{sdk.NewCoin(suite.EvmDenom(), sdk.NewIntFromBigInt(txData.Fee()))}
err = ante.DeductFees(suite.app.BankKeeper, suite.ctx, suite.app.AccountKeeper.GetAccount(ctx, msg.GetFrom()), fees)
fees := sdk.Coins{sdk.NewCoin(suite.EvmDenom(), sdkmath.NewIntFromBigInt(txData.Fee()))}
err = authante.DeductFees(suite.app.BankKeeper, suite.ctx, suite.app.AccountKeeper.GetAccount(ctx, msg.GetFrom()), fees)
require.NoError(b, err)
rsp, err := suite.app.EvmKeeper.EthereumTx(sdk.WrapSDKContext(ctx), msg)
+85 -74
View File
@@ -15,6 +15,7 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
@@ -88,6 +89,7 @@ func (k Keeper) CosmosAccount(c context.Context, req *types.QueryCosmosAccountRe
return &res, nil
}
// ValidatorAccount implements the Query/Balance gRPC method
func (k Keeper) ValidatorAccount(c context.Context, req *types.QueryValidatorAccountRequest) (*types.QueryValidatorAccountResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
@@ -104,7 +106,7 @@ func (k Keeper) ValidatorAccount(c context.Context, req *types.QueryValidatorAcc
validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr)
if !found {
return nil, nil
return nil, fmt.Errorf("validator not found for %s", consAddr.String())
}
accAddr := sdk.AccAddress(validator.GetOperator())
@@ -362,8 +364,15 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ
return nil, status.Errorf(codes.InvalidArgument, "output limit cannot be negative, got %d", req.TraceConfig.Limit)
}
// minus one to get the context of block beginning
contextHeight := req.BlockNumber - 1
if contextHeight < 1 {
// 0 is a special value in `ContextWithHeight`
contextHeight = 1
}
ctx := sdk.UnwrapSDKContext(c)
ctx = ctx.WithBlockHeight(req.BlockNumber)
ctx = ctx.WithBlockHeight(contextHeight)
ctx = ctx.WithBlockTime(req.BlockTime)
ctx = ctx.WithHeaderHash(common.Hex2Bytes(req.BlockHash))
@@ -391,7 +400,10 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ
tx := req.Msg.AsTransaction()
txConfig.TxHash = tx.Hash()
txConfig.TxIndex++
if len(req.Predecessors) > 0 {
txConfig.TxIndex++
}
result, _, err := k.traceTx(ctx, cfg, txConfig, signer, tx, req.TraceConfig, false)
if err != nil {
// error will be returned with detail status from traceTx
@@ -420,8 +432,15 @@ func (k Keeper) TraceBlock(c context.Context, req *types.QueryTraceBlockRequest)
return nil, status.Errorf(codes.InvalidArgument, "output limit cannot be negative, got %d", req.TraceConfig.Limit)
}
// minus one to get the context of block beginning
contextHeight := req.BlockNumber - 1
if contextHeight < 1 {
// 0 is a special value in `ContextWithHeight`
contextHeight = 1
}
ctx := sdk.UnwrapSDKContext(c)
ctx = ctx.WithBlockHeight(req.BlockNumber)
ctx = ctx.WithBlockHeight(contextHeight)
ctx = ctx.WithBlockTime(req.BlockTime)
ctx = ctx.WithHeaderHash(common.Hex2Bytes(req.BlockHash))
@@ -471,101 +490,93 @@ func (k *Keeper) traceTx(
) (*interface{}, uint, error) {
// Assemble the structured logger or the JavaScript tracer
var (
tracer vm.EVMLogger
tracer tracers.Tracer
overrides *ethparams.ChainConfig
err error
timeout = defaultTraceTimeout
)
msg, err := tx.AsMessage(signer, cfg.BaseFee)
if err != nil {
return nil, 0, status.Error(codes.Internal, err.Error())
}
if traceConfig != nil && traceConfig.Overrides != nil {
if traceConfig == nil {
traceConfig = &types.TraceConfig{}
}
if traceConfig.Overrides != nil {
overrides = traceConfig.Overrides.EthereumConfig(cfg.ChainConfig.ChainID)
}
switch {
case traceConfig != nil && traceConfig.Tracer != "":
timeout := defaultTraceTimeout
// TODO: change timeout to time.duration
// Used string to comply with go ethereum
if traceConfig.Timeout != "" {
timeout, err = time.ParseDuration(traceConfig.Timeout)
if err != nil {
return nil, 0, status.Errorf(codes.InvalidArgument, "timeout value: %s", err.Error())
}
}
logConfig := logger.Config{
EnableMemory: traceConfig.EnableMemory,
DisableStorage: traceConfig.DisableStorage,
DisableStack: traceConfig.DisableStack,
EnableReturnData: traceConfig.EnableReturnData,
Debug: traceConfig.Debug,
Limit: int(traceConfig.Limit),
Overrides: overrides,
}
tCtx := &tracers.Context{
BlockHash: txConfig.BlockHash,
TxIndex: int(txConfig.TxIndex),
TxHash: txConfig.TxHash,
}
tracer = logger.NewStructLogger(&logConfig)
// Construct the JavaScript tracer to execute with
tCtx := &tracers.Context{
BlockHash: txConfig.BlockHash,
TxIndex: int(txConfig.TxIndex),
TxHash: txConfig.TxHash,
}
if traceConfig.Tracer != "" {
if tracer, err = tracers.New(traceConfig.Tracer, tCtx); err != nil {
return nil, 0, status.Error(codes.Internal, err.Error())
}
// Handle timeouts and RPC cancellations
deadlineCtx, cancel := context.WithTimeout(ctx.Context(), timeout)
defer cancel()
go func() {
<-deadlineCtx.Done()
if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
tracer.(tracers.Tracer).Stop(errors.New("execution timeout"))
}
}()
case traceConfig != nil:
logConfig := logger.Config{
EnableMemory: traceConfig.EnableMemory,
DisableStorage: traceConfig.DisableStorage,
DisableStack: traceConfig.DisableStack,
EnableReturnData: traceConfig.EnableReturnData,
Debug: traceConfig.Debug,
Limit: int(traceConfig.Limit),
Overrides: overrides,
}
tracer = logger.NewStructLogger(&logConfig)
default:
tracer = types.NewTracer(types.TracerStruct, msg, cfg.ChainConfig, ctx.BlockHeight())
}
// Define a meaningful timeout of a single transaction trace
if traceConfig.Timeout != "" {
if timeout, err = time.ParseDuration(traceConfig.Timeout); err != nil {
return nil, 0, status.Errorf(codes.InvalidArgument, "timeout value: %s", err.Error())
}
}
// Handle timeouts and RPC cancellations
deadlineCtx, cancel := context.WithTimeout(ctx.Context(), timeout)
defer cancel()
go func() {
<-deadlineCtx.Done()
if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
tracer.Stop(errors.New("execution timeout"))
}
}()
res, err := k.ApplyMessageWithConfig(ctx, msg, tracer, commitMessage, cfg, txConfig)
if err != nil {
return nil, 0, status.Error(codes.Internal, err.Error())
}
var result interface{}
// Depending on the tracer type, format and return the trace result data.
switch tracer := tracer.(type) {
case *logger.StructLogger:
returnVal := ""
revert := res.Revert()
if len(revert) > 0 {
returnVal = fmt.Sprintf("%x", revert)
} else {
returnVal = fmt.Sprintf("%x", res.Return())
}
result = types.ExecutionResult{
Gas: res.GasUsed,
Failed: res.Failed(),
ReturnValue: returnVal,
StructLogs: types.FormatLogs(tracer.StructLogs()),
}
case tracers.Tracer:
result, err = tracer.GetResult()
if err != nil {
return nil, 0, status.Error(codes.Internal, err.Error())
}
default:
return nil, 0, status.Errorf(codes.InvalidArgument, "invalid tracer type %T", tracer)
result, err = tracer.GetResult()
if err != nil {
return nil, 0, status.Error(codes.Internal, err.Error())
}
return &result, txConfig.LogIndex + uint(len(res.Logs)), nil
}
// BaseFee implements the Query/BaseFee gRPC method
func (k Keeper) BaseFee(c context.Context, _ *types.QueryBaseFeeRequest) (*types.QueryBaseFeeResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
params := k.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID)
baseFee := k.GetBaseFee(ctx, ethCfg)
res := &types.QueryBaseFeeResponse{}
if baseFee != nil {
aux := sdkmath.NewIntFromBigInt(baseFee)
res.BaseFee = &aux
}
return res, nil
}
+115 -42
View File
@@ -5,12 +5,15 @@ import (
"fmt"
"math/big"
"cosmossdk.io/math"
sdkmath "cosmossdk.io/math"
"github.com/cerc-io/laconicd/x/evm/statedb"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
ethlogger "github.com/ethereum/go-ethereum/eth/tracers/logger"
ethparams "github.com/ethereum/go-ethereum/params"
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -523,7 +526,7 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
}, false, 0, false},
// estimate gas of an erc20 contract deployment, the exact gas number is checked with geth
{"contract deployment", func() {
ctorArgs, err := types.ERC20Contract.ABI.Pack("", &suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
ctorArgs, err := types.ERC20Contract.ABI.Pack("", &suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Require().NoError(err)
data := append(types.ERC20Contract.Bin, ctorArgs...)
args = types.TransactionArgs{
@@ -533,7 +536,7 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
}, true, 1186778, false},
// estimate gas of an erc20 transfer, the exact gas number is checked with geth
{"erc20 transfer", func() {
contractAddr := suite.DeployTestContract(suite.T(), suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
transferData, err := types.ERC20Contract.ABI.Pack("transfer", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000))
suite.Require().NoError(err)
@@ -558,7 +561,7 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
gasCap = 20000
}, false, 0, true},
{"contract deployment w/ enableFeemarket", func() {
ctorArgs, err := types.ERC20Contract.ABI.Pack("", &suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
ctorArgs, err := types.ERC20Contract.ABI.Pack("", &suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Require().NoError(err)
data := append(types.ERC20Contract.Bin, ctorArgs...)
args = types.TransactionArgs{
@@ -567,7 +570,7 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
}
}, true, 1186778, true},
{"erc20 transfer w/ enableFeemarket", func() {
contractAddr := suite.DeployTestContract(suite.T(), suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
transferData, err := types.ERC20Contract.ABI.Pack("transfer", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000))
suite.Require().NoError(err)
@@ -606,7 +609,6 @@ func (suite *KeeperTestSuite) TestTraceTx() {
var (
txMsg *types.MsgEthereumTx
traceConfig *types.TraceConfig
txIndex uint64
predecessors []*types.MsgEthereumTx
)
@@ -614,23 +616,21 @@ func (suite *KeeperTestSuite) TestTraceTx() {
msg string
malleate func()
expPass bool
traceResponse []byte
traceResponse string
enableFeemarket bool
}{
{
msg: "default trace",
malleate: func() {
txIndex = 0
traceConfig = nil
predecessors = []*types.MsgEthereumTx{}
},
expPass: true,
traceResponse: []byte{0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55, 0x53, 0x48, 0x31, 0x22, 0x2c, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a},
traceResponse: "{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PUSH1\",\"gas\":",
},
{
msg: "default trace with filtered response",
malleate: func() {
txIndex = 0
traceConfig = &types.TraceConfig{
DisableStack: true,
DisableStorage: true,
@@ -639,25 +639,23 @@ func (suite *KeeperTestSuite) TestTraceTx() {
predecessors = []*types.MsgEthereumTx{}
},
expPass: true,
traceResponse: []byte{0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55, 0x53, 0x48, 0x31, 0x22, 0x2c, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a},
traceResponse: "{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PUSH1\",\"gas\":",
enableFeemarket: false,
},
{
msg: "javascript tracer",
malleate: func() {
txIndex = 0
traceConfig = &types.TraceConfig{
Tracer: "{data: [], fault: function(log) {}, step: function(log) { if(log.op.toString() == \"CALL\") this.data.push(log.stack.peek(0)); }, result: function() { return this.data; }}",
}
predecessors = []*types.MsgEthereumTx{}
},
expPass: true,
traceResponse: []byte{0x5b, 0x5d},
traceResponse: "[]",
},
{
msg: "default trace with enableFeemarket",
malleate: func() {
txIndex = 0
traceConfig = &types.TraceConfig{
DisableStack: true,
DisableStorage: true,
@@ -666,26 +664,24 @@ func (suite *KeeperTestSuite) TestTraceTx() {
predecessors = []*types.MsgEthereumTx{}
},
expPass: true,
traceResponse: []byte{0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55, 0x53, 0x48, 0x31, 0x22, 0x2c, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a},
traceResponse: "{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PUSH1\",\"gas\":",
enableFeemarket: true,
},
{
msg: "javascript tracer with enableFeemarket",
malleate: func() {
txIndex = 0
traceConfig = &types.TraceConfig{
Tracer: "{data: [], fault: function(log) {}, step: function(log) { if(log.op.toString() == \"CALL\") this.data.push(log.stack.peek(0)); }, result: function() { return this.data; }}",
}
predecessors = []*types.MsgEthereumTx{}
},
expPass: true,
traceResponse: []byte{0x5b, 0x5d},
traceResponse: "[]",
enableFeemarket: true,
},
{
msg: "default tracer with predecessors",
malleate: func() {
txIndex = 1
traceConfig = nil
// increase nonce to avoid address collision
@@ -693,17 +689,17 @@ func (suite *KeeperTestSuite) TestTraceTx() {
vmdb.SetNonce(suite.address, vmdb.GetNonce(suite.address)+1)
suite.Require().NoError(vmdb.Commit())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
// Generate token transfer transaction
firstTx := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), math.NewIntWithDecimal(1, 18).BigInt())
txMsg = suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), math.NewIntWithDecimal(1, 18).BigInt())
firstTx := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), sdkmath.NewIntWithDecimal(1, 18).BigInt())
txMsg = suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), sdkmath.NewIntWithDecimal(1, 18).BigInt())
suite.Commit()
predecessors = append(predecessors, firstTx)
},
expPass: true,
traceResponse: []byte{0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55, 0x53, 0x48, 0x31, 0x22, 0x2c, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a},
traceResponse: "{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PUSH1\",\"gas\":",
enableFeemarket: false,
},
}
@@ -713,17 +709,16 @@ func (suite *KeeperTestSuite) TestTraceTx() {
suite.enableFeemarket = tc.enableFeemarket
suite.SetupTest()
// Deploy contract
contractAddr := suite.DeployTestContract(suite.T(), suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
// Generate token transfer transaction
txMsg = suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), math.NewIntWithDecimal(1, 18).BigInt())
txMsg = suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), sdkmath.NewIntWithDecimal(1, 18).BigInt())
suite.Commit()
tc.malleate()
traceReq := types.QueryTraceTxRequest{
Msg: txMsg,
TraceConfig: traceConfig,
TxIndex: txIndex,
Predecessors: predecessors,
}
res, err := suite.queryClient.TraceTx(sdk.WrapSDKContext(suite.ctx), &traceReq)
@@ -733,9 +728,14 @@ func (suite *KeeperTestSuite) TestTraceTx() {
suite.Require().NoError(err)
// if data is to big, slice the result
if len(res.Data) > 150 {
suite.Require().Equal(tc.traceResponse, res.Data[:150])
suite.Require().Equal(tc.traceResponse, string(res.Data[:150]))
} else {
suite.Require().Equal(tc.traceResponse, res.Data)
suite.Require().Equal(tc.traceResponse, string(res.Data))
}
if traceConfig == nil || traceConfig.Tracer == "" {
var result ethlogger.ExecutionResult
suite.Require().NoError(json.Unmarshal(res.Data, &result))
suite.Require().Positive(result.Gas)
}
} else {
suite.Require().Error(err)
@@ -756,7 +756,7 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
msg string
malleate func()
expPass bool
traceResponse []byte
traceResponse string
enableFeemarket bool
}{
{
@@ -765,7 +765,7 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
traceConfig = nil
},
expPass: true,
traceResponse: []byte{0x5b, 0x7b, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55},
traceResponse: "[{\"result\":{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PU",
},
{
msg: "filtered trace",
@@ -777,7 +777,7 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
}
},
expPass: true,
traceResponse: []byte{0x5b, 0x7b, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55},
traceResponse: "[{\"result\":{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PU",
},
{
msg: "javascript tracer",
@@ -787,7 +787,7 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
}
},
expPass: true,
traceResponse: []byte{0x5b, 0x7b, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x5b, 0x5d, 0x7d, 0x5d},
traceResponse: "[{\"result\":[]}]",
},
{
msg: "default trace with enableFeemarket and filtered return",
@@ -799,7 +799,7 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
}
},
expPass: true,
traceResponse: []byte{0x5b, 0x7b, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55},
traceResponse: "[{\"result\":{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PU",
enableFeemarket: true,
},
{
@@ -810,7 +810,7 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
}
},
expPass: true,
traceResponse: []byte{0x5b, 0x7b, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x5b, 0x5d, 0x7d, 0x5d},
traceResponse: "[{\"result\":[]}]",
enableFeemarket: true,
},
{
@@ -823,17 +823,17 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
vmdb.SetNonce(suite.address, vmdb.GetNonce(suite.address)+1)
suite.Require().NoError(vmdb.Commit())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
// create multiple transactions in the same block
firstTx := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), math.NewIntWithDecimal(1, 18).BigInt())
secondTx := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), math.NewIntWithDecimal(1, 18).BigInt())
firstTx := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), sdkmath.NewIntWithDecimal(1, 18).BigInt())
secondTx := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), sdkmath.NewIntWithDecimal(1, 18).BigInt())
suite.Commit()
// overwrite txs to include only the ones on new block
txs = append([]*types.MsgEthereumTx{}, firstTx, secondTx)
},
expPass: true,
traceResponse: []byte{0x5b, 0x7b, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55},
traceResponse: "[{\"result\":{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PU",
enableFeemarket: false,
},
}
@@ -844,10 +844,10 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
suite.enableFeemarket = tc.enableFeemarket
suite.SetupTest()
// Deploy contract
contractAddr := suite.DeployTestContract(suite.T(), suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
// Generate token transfer transaction
txMsg := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), math.NewIntWithDecimal(1, 18).BigInt())
txMsg := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), sdkmath.NewIntWithDecimal(1, 18).BigInt())
suite.Commit()
txs = append(txs, txMsg)
@@ -863,9 +863,9 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
suite.Require().NoError(err)
// if data is to big, slice the result
if len(res.Data) > 150 {
suite.Require().Equal(tc.traceResponse, res.Data[:150])
suite.Require().Equal(tc.traceResponse, string(res.Data[:150]))
} else {
suite.Require().Equal(tc.traceResponse, res.Data)
suite.Require().Equal(tc.traceResponse, string(res.Data))
}
} else {
suite.Require().Error(err)
@@ -882,7 +882,7 @@ func (suite *KeeperTestSuite) TestNonceInQuery() {
suite.Require().NoError(err)
address := common.BytesToAddress(priv.PubKey().Address().Bytes())
suite.Require().Equal(uint64(0), suite.app.EvmKeeper.GetNonce(suite.ctx, address))
supply := math.NewIntWithDecimal(1000, 18).BigInt()
supply := sdkmath.NewIntWithDecimal(1000, 18).BigInt()
// accupy nonce 0
_ = suite.DeployTestContract(suite.T(), address, supply)
@@ -908,3 +908,76 @@ func (suite *KeeperTestSuite) TestNonceInQuery() {
})
suite.Require().NoError(err)
}
func (suite *KeeperTestSuite) TestQueryBaseFee() {
var (
aux sdkmath.Int
expRes *types.QueryBaseFeeResponse
)
testCases := []struct {
name string
malleate func()
expPass bool
enableFeemarket bool
enableLondonHF bool
}{
{
"pass - default Base Fee",
func() {
initialBaseFee := sdkmath.NewInt(ethparams.InitialBaseFee)
expRes = &types.QueryBaseFeeResponse{BaseFee: &initialBaseFee}
},
true, true, true,
},
{
"pass - non-nil Base Fee",
func() {
baseFee := sdk.OneInt().BigInt()
suite.app.FeeMarketKeeper.SetBaseFee(suite.ctx, baseFee)
aux = sdkmath.NewIntFromBigInt(baseFee)
expRes = &types.QueryBaseFeeResponse{BaseFee: &aux}
},
true, true, true,
},
{
"pass - nil Base Fee when london hardfork not activated",
func() {
baseFee := sdk.OneInt().BigInt()
suite.app.FeeMarketKeeper.SetBaseFee(suite.ctx, baseFee)
expRes = &types.QueryBaseFeeResponse{}
},
true, true, false,
},
{
"pass - zero Base Fee when feemarket not activated",
func() {
baseFee := sdk.ZeroInt()
expRes = &types.QueryBaseFeeResponse{BaseFee: &baseFee}
},
true, false, true,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.enableFeemarket = tc.enableFeemarket
suite.enableLondonHF = tc.enableLondonHF
suite.SetupTest()
tc.malleate()
res, err := suite.queryClient.BaseFee(suite.ctx.Context(), &types.QueryBaseFeeRequest{})
if tc.expPass {
suite.Require().NotNil(res)
suite.Require().Equal(expRes, res, tc.name)
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
suite.enableFeemarket = false
suite.enableLondonHF = true
}
+3 -3
View File
@@ -4,7 +4,7 @@ import (
"github.com/cerc-io/laconicd/x/evm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
@@ -19,9 +19,9 @@ func NewMultiEvmHooks(hooks ...types.EvmHooks) MultiEvmHooks {
}
// PostTxProcessing delegate the call to underlying hooks
func (mh MultiEvmHooks) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
func (mh MultiEvmHooks) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
for i := range mh {
if err := mh[i].PostTxProcessing(ctx, from, to, receipt); err != nil {
if err := mh[i].PostTxProcessing(ctx, msg, receipt); err != nil {
return sdkerrors.Wrapf(err, "EVM hook %T failed", mh[i])
}
}
+4 -3
View File
@@ -6,6 +6,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/cerc-io/laconicd/x/evm/keeper"
@@ -18,7 +19,7 @@ type LogRecordHook struct {
Logs []*ethtypes.Log
}
func (dh *LogRecordHook) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
func (dh *LogRecordHook) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
dh.Logs = receipt.Logs
return nil
}
@@ -26,7 +27,7 @@ func (dh *LogRecordHook) PostTxProcessing(ctx sdk.Context, from common.Address,
// FailureHook always fail
type FailureHook struct{}
func (dh FailureHook) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
func (dh FailureHook) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
return errors.New("post tx processing failed")
}
@@ -81,7 +82,7 @@ func (suite *KeeperTestSuite) TestEvmHooks() {
TxHash: txHash,
Logs: logs,
}
result := k.PostTxProcessing(ctx, common.Address{}, nil, receipt)
result := k.PostTxProcessing(ctx, ethtypes.Message{}, receipt)
tc.expFunc(hook, result)
}
+290
View File
@@ -0,0 +1,290 @@
package keeper_test
import (
"encoding/json"
"math/big"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/cerc-io/laconicd/app"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
"github.com/cerc-io/laconicd/encoding"
"github.com/cerc-io/laconicd/tests"
"github.com/cerc-io/laconicd/testutil"
"github.com/cerc-io/laconicd/x/feemarket/types"
"github.com/cosmos/cosmos-sdk/baseapp"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
"github.com/cosmos/cosmos-sdk/simapp"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
)
var _ = Describe("Feemarket", func() {
var privKey *ethsecp256k1.PrivKey
Describe("Performing EVM transactions", func() {
type txParams struct {
gasLimit uint64
gasPrice *big.Int
gasFeeCap *big.Int
gasTipCap *big.Int
accesses *ethtypes.AccessList
}
type getprices func() txParams
Context("with MinGasPrices (feemarket param) < BaseFee (feemarket)", func() {
var (
baseFee int64
minGasPrices int64
)
BeforeEach(func() {
baseFee = 10_000_000_000
minGasPrices = baseFee - 5_000_000_000
// Note that the tests run the same transactions with `gasLimit =
// 100_000`. With the fee calculation `Fee = (baseFee + tip) * gasLimit`,
// a `minGasPrices = 5_000_000_000` results in `minGlobalFee =
// 500_000_000_000_000`
privKey, _ = setupTestWithContext("1", sdk.NewDec(minGasPrices), sdk.NewInt(baseFee))
})
Context("during CheckTx", func() {
DescribeTable("should accept transactions with gas Limit > 0",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasLimit, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := checkEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{100000, big.NewInt(baseFee), nil, nil, nil}
}),
Entry("dynamic tx", func() txParams {
return txParams{100000, nil, big.NewInt(baseFee), big.NewInt(0), &ethtypes.AccessList{}}
}),
)
DescribeTable("should not accept transactions with gas Limit > 0",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasLimit, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := checkEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(false), "transaction should have succeeded", res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{0, big.NewInt(baseFee), nil, nil, nil}
}),
Entry("dynamic tx", func() txParams {
return txParams{0, nil, big.NewInt(baseFee), big.NewInt(0), &ethtypes.AccessList{}}
}),
)
})
Context("during DeliverTx", func() {
DescribeTable("should accept transactions with gas Limit > 0",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasLimit, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := deliverEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{100000, big.NewInt(baseFee), nil, nil, nil}
}),
Entry("dynamic tx", func() txParams {
return txParams{100000, nil, big.NewInt(baseFee), big.NewInt(0), &ethtypes.AccessList{}}
}),
)
DescribeTable("should not accept transactions with gas Limit > 0",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasLimit, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := checkEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(false), "transaction should have succeeded", res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{0, big.NewInt(baseFee), nil, nil, nil}
}),
Entry("dynamic tx", func() txParams {
return txParams{0, nil, big.NewInt(baseFee), big.NewInt(0), &ethtypes.AccessList{}}
}),
)
})
})
})
})
// setupTestWithContext sets up a test chain with an example Cosmos send msg,
// given a local (validator config) and a gloabl (feemarket param) minGasPrice
func setupTestWithContext(valMinGasPrice string, minGasPrice sdk.Dec, baseFee sdk.Int) (*ethsecp256k1.PrivKey, banktypes.MsgSend) {
privKey, msg := setupTest(valMinGasPrice + s.denom)
params := types.DefaultParams()
params.MinGasPrice = minGasPrice
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
s.app.FeeMarketKeeper.SetBaseFee(s.ctx, baseFee.BigInt())
s.Commit()
return privKey, msg
}
func setupTest(localMinGasPrices string) (*ethsecp256k1.PrivKey, banktypes.MsgSend) {
setupChain(localMinGasPrices)
privKey, address := generateKey()
amount, ok := sdk.NewIntFromString("10000000000000000000")
s.Require().True(ok)
initBalance := sdk.Coins{sdk.Coin{
Denom: s.denom,
Amount: amount,
}}
testutil.FundAccount(s.app.BankKeeper, s.ctx, address, initBalance)
msg := banktypes.MsgSend{
FromAddress: address.String(),
ToAddress: address.String(),
Amount: sdk.Coins{sdk.Coin{
Denom: s.denom,
Amount: sdk.NewInt(10000),
}},
}
s.Commit()
return privKey, msg
}
func setupChain(localMinGasPricesStr string) {
// Initialize the app, so we can use SetMinGasPrices to set the
// validator-specific min-gas-prices setting
db := dbm.NewMemDB()
newapp := app.NewEthermintApp(
log.NewNopLogger(),
db,
nil,
true,
map[int64]bool{},
app.DefaultNodeHome,
5,
encoding.MakeConfig(app.ModuleBasics),
simapp.EmptyAppOptions{},
baseapp.SetMinGasPrices(localMinGasPricesStr),
)
genesisState := app.NewTestGenesisState(newapp.AppCodec())
genesisState[types.ModuleName] = newapp.AppCodec().MustMarshalJSON(types.DefaultGenesisState())
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
s.Require().NoError(err)
// Initialize the chain
newapp.InitChain(
abci.RequestInitChain{
ChainId: "ethermint_9000-1",
Validators: []abci.ValidatorUpdate{},
AppStateBytes: stateBytes,
ConsensusParams: app.DefaultConsensusParams,
},
)
s.app = newapp
s.SetupApp(false)
}
func generateKey() (*ethsecp256k1.PrivKey, sdk.AccAddress) {
address, priv := tests.NewAddrKey()
return priv.(*ethsecp256k1.PrivKey), sdk.AccAddress(address.Bytes())
}
func getNonce(addressBytes []byte) uint64 {
return s.app.EvmKeeper.GetNonce(
s.ctx,
common.BytesToAddress(addressBytes),
)
}
func buildEthTx(
priv *ethsecp256k1.PrivKey,
to *common.Address,
gasLimit uint64,
gasPrice *big.Int,
gasFeeCap *big.Int,
gasTipCap *big.Int,
accesses *ethtypes.AccessList,
) *evmtypes.MsgEthereumTx {
chainID := s.app.EvmKeeper.ChainID()
from := common.BytesToAddress(priv.PubKey().Address().Bytes())
nonce := getNonce(from.Bytes())
data := make([]byte, 0)
msgEthereumTx := evmtypes.NewTx(
chainID,
nonce,
to,
nil,
gasLimit,
gasPrice,
gasFeeCap,
gasTipCap,
data,
accesses,
)
msgEthereumTx.From = from.String()
return msgEthereumTx
}
func prepareEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) []byte {
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
option, err := codectypes.NewAnyWithValue(&evmtypes.ExtensionOptionsEthereumTx{})
s.Require().NoError(err)
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
s.Require().True(ok)
builder.SetExtensionOptions(option)
err = msgEthereumTx.Sign(s.ethSigner, tests.NewSigner(priv))
s.Require().NoError(err)
// A valid msg should have empty `From`
msgEthereumTx.From = ""
err = txBuilder.SetMsgs(msgEthereumTx)
s.Require().NoError(err)
txData, err := evmtypes.UnpackTxData(msgEthereumTx.Data)
s.Require().NoError(err)
evmDenom := s.app.EvmKeeper.GetParams(s.ctx).EvmDenom
fees := sdk.Coins{{Denom: evmDenom, Amount: sdk.NewIntFromBigInt(txData.Fee())}}
builder.SetFeeAmount(fees)
builder.SetGasLimit(msgEthereumTx.GetGas())
// bz are bytes to be broadcasted over the network
bz, err := encodingConfig.TxConfig.TxEncoder()(txBuilder.GetTx())
s.Require().NoError(err)
return bz
}
func checkEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) abci.ResponseCheckTx {
bz := prepareEthTx(priv, msgEthereumTx)
req := abci.RequestCheckTx{Tx: bz}
res := s.app.BaseApp.CheckTx(req)
return res
}
func deliverEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) abci.ResponseDeliverTx {
bz := prepareEthTx(priv, msgEthereumTx)
req := abci.RequestDeliverTx{Tx: bz}
res := s.app.BaseApp.DeliverTx(req)
return res
}
+51 -18
View File
@@ -19,6 +19,7 @@ import (
ethermint "github.com/cerc-io/laconicd/types"
"github.com/cerc-io/laconicd/x/evm/statedb"
"github.com/cerc-io/laconicd/x/evm/types"
evm "github.com/cerc-io/laconicd/x/evm/vm"
)
// Keeper grants access to the EVM module state and implements the go-ethereum StateDB interface.
@@ -54,14 +55,25 @@ type Keeper struct {
// EVM Hooks for tx post-processing
hooks types.EvmHooks
// custom stateless precompiled smart contracts
customPrecompiles evm.PrecompiledContracts
// evm constructor function
evmConstructor evm.Constructor
}
// NewKeeper generates new evm module keeper
func NewKeeper(
cdc codec.BinaryCodec,
storeKey, transientKey storetypes.StoreKey, paramSpace paramtypes.Subspace,
ak types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper,
storeKey, transientKey storetypes.StoreKey,
paramSpace paramtypes.Subspace,
ak types.AccountKeeper,
bankKeeper types.BankKeeper,
sk types.StakingKeeper,
fmk types.FeeMarketKeeper,
customPrecompiles evm.PrecompiledContracts,
evmConstructor evm.Constructor,
tracer string,
) *Keeper {
// ensure evm module account is set
@@ -76,15 +88,17 @@ func NewKeeper(
// NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations
return &Keeper{
cdc: cdc,
paramSpace: paramSpace,
accountKeeper: ak,
bankKeeper: bankKeeper,
stakingKeeper: sk,
feeMarketKeeper: fmk,
storeKey: storeKey,
transientKey: transientKey,
tracer: tracer,
cdc: cdc,
paramSpace: paramSpace,
accountKeeper: ak,
bankKeeper: bankKeeper,
stakingKeeper: sk,
feeMarketKeeper: fmk,
storeKey: storeKey,
transientKey: transientKey,
customPrecompiles: customPrecompiles,
evmConstructor: evmConstructor,
tracer: tracer,
}
}
@@ -222,11 +236,11 @@ func (k *Keeper) SetHooks(eh types.EvmHooks) *Keeper {
}
// PostTxProcessing delegate the call to the hooks. If no hook has been registered, this function returns with a `nil` error
func (k *Keeper) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
func (k *Keeper) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
if k.hooks == nil {
return nil
}
return k.hooks.PostTxProcessing(ctx, from, to, receipt)
return k.hooks.PostTxProcessing(ctx, msg, receipt)
}
// Tracer return a default vm.Tracer based on current keeper state
@@ -283,17 +297,26 @@ func (k *Keeper) GetNonce(ctx sdk.Context, addr common.Address) uint64 {
// GetBalance load account's balance of gas token
func (k *Keeper) GetBalance(ctx sdk.Context, addr common.Address) *big.Int {
cosmosAddr := sdk.AccAddress(addr.Bytes())
params := k.GetParams(ctx)
coin := k.bankKeeper.GetBalance(ctx, cosmosAddr, params.EvmDenom)
evmDenom := ""
k.paramSpace.GetIfExists(ctx, types.ParamStoreKeyEVMDenom, &evmDenom)
// if node is pruned, params is empty. Return invalid value
if evmDenom == "" {
return big.NewInt(-1)
}
coin := k.bankKeeper.GetBalance(ctx, cosmosAddr, evmDenom)
return coin.Amount.BigInt()
}
// BaseFee returns current base fee, return values:
// GetBaseFee returns current base fee, return values:
// - `nil`: london hardfork not enabled.
// - `0`: london hardfork enabled but feemarket is not enabled.
// - `n`: both london hardfork and feemarket are enabled.
func (k Keeper) BaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int {
if !types.IsLondon(ethCfg, ctx.BlockHeight()) {
func (k Keeper) GetBaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int {
return k.getBaseFee(ctx, types.IsLondon(ethCfg, ctx.BlockHeight()))
}
func (k Keeper) getBaseFee(ctx sdk.Context, london bool) *big.Int {
if !london {
return nil
}
baseFee := k.feeMarketKeeper.GetBaseFee(ctx)
@@ -304,6 +327,16 @@ func (k Keeper) BaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int {
return baseFee
}
// GetMinGasMultiplier returns the MinGasMultiplier param from the fee market module
func (k Keeper) GetMinGasMultiplier(ctx sdk.Context) sdk.Dec {
fmkParmas := k.feeMarketKeeper.GetParams(ctx)
if fmkParmas.MinGasMultiplier.IsNil() {
// in case we are executing eth_call on a legacy block, returns a zero value.
return sdk.ZeroDec()
}
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)
+67 -28
View File
@@ -8,8 +8,10 @@ import (
"testing"
"time"
cmath "cosmossdk.io/math"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
sdkmath "cosmossdk.io/math"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
@@ -21,8 +23,9 @@ import (
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/bank/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
tmjson "github.com/tendermint/tendermint/libs/json"
"github.com/cerc-io/laconicd/app"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
@@ -32,6 +35,7 @@ import (
ethermint "github.com/cerc-io/laconicd/types"
"github.com/cerc-io/laconicd/x/evm/statedb"
"github.com/cerc-io/laconicd/x/evm/types"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -46,7 +50,7 @@ import (
"github.com/tendermint/tendermint/version"
)
var testTokens = cmath.NewIntWithDecimal(1000, 18)
var testTokens = sdkmath.NewIntWithDecimal(1000, 18)
type KeeperTestSuite struct {
suite.Suite
@@ -67,12 +71,31 @@ type KeeperTestSuite struct {
enableFeemarket bool
enableLondonHF bool
mintFeeCollector bool
denom string
}
/// DoSetupTest setup test environment, it uses`require.TestingT` to support both `testing.T` and `testing.B`.
func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
checkTx := false
var s *KeeperTestSuite
func TestKeeperTestSuite(t *testing.T) {
s = new(KeeperTestSuite)
s.enableFeemarket = false
s.enableLondonHF = true
suite.Run(t, s)
// Run Ginkgo integration tests
RegisterFailHandler(Fail)
RunSpecs(t, "Keeper Suite")
}
func (suite *KeeperTestSuite) SetupTest() {
checkTx := false
suite.app = app.Setup(checkTx, nil)
suite.SetupApp(checkTx)
}
// SetupApp setup test environment, it uses`require.TestingT` to support both `testing.T` and `testing.B`.
func (suite *KeeperTestSuite) SetupApp(checkTx bool) {
t := suite.T()
// account key, use a constant account to keep unit test deterministic.
ecdsaPriv, err := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
require.NoError(t, err)
@@ -87,7 +110,7 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
require.NoError(t, err)
suite.consAddress = sdk.ConsAddress(priv.PubKey().Address())
suite.app = app.Setup(suite.T(), checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
suite.app = app.Setup(checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
feemarketGenesis := feemarkettypes.DefaultGenesisState()
if suite.enableFeemarket {
feemarketGenesis.Params.EnableHeight = 1
@@ -98,15 +121,48 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
genesis[feemarkettypes.ModuleName] = app.AppCodec().MustMarshalJSON(feemarketGenesis)
if !suite.enableLondonHF {
evmGenesis := types.DefaultGenesisState()
maxInt := sdk.NewInt(math.MaxInt64)
maxInt := sdkmath.NewInt(math.MaxInt64)
evmGenesis.Params.ChainConfig.LondonBlock = &maxInt
evmGenesis.Params.ChainConfig.ArrowGlacierBlock = &maxInt
evmGenesis.Params.ChainConfig.MergeForkBlock = &maxInt
evmGenesis.Params.ChainConfig.GrayGlacierBlock = &maxInt
evmGenesis.Params.ChainConfig.MergeNetsplitBlock = &maxInt
genesis[types.ModuleName] = app.AppCodec().MustMarshalJSON(evmGenesis)
}
return genesis
})
if suite.mintFeeCollector {
// mint some coin to fee collector
coins := sdk.NewCoins(sdk.NewCoin(types.DefaultEVMDenom, sdkmath.NewInt(int64(params.TxGas)-1)))
genesisState := app.NewTestGenesisState(suite.app.AppCodec())
balances := []banktypes.Balance{
{
Address: suite.app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName).String(),
Coins: coins,
},
}
var bankGenesis banktypes.GenesisState
suite.app.AppCodec().MustUnmarshalJSON(genesisState[banktypes.ModuleName], &bankGenesis)
// Update balances and total supply
bankGenesis.Balances = append(bankGenesis.Balances, balances...)
bankGenesis.Supply = bankGenesis.Supply.Add(coins...)
genesisState[banktypes.ModuleName] = suite.app.AppCodec().MustMarshalJSON(&bankGenesis)
// we marshal the genesisState of all module to a byte array
stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)
// Initialize the chain
suite.app.InitChain(
abci.RequestInitChain{
ChainId: "ethermint_9000-1",
Validators: []abci.ValidatorUpdate{},
ConsensusParams: app.DefaultConsensusParams,
AppStateBytes: stateBytes,
},
)
}
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{
Height: 1,
ChainID: "ethermint_9000-1",
@@ -131,12 +187,6 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
LastResultsHash: tmhash.Sum([]byte("last_result")),
})
if suite.mintFeeCollector {
// mint some coin to fee collector
coins := sdk.NewCoins(sdk.NewCoin(types.DefaultEVMDenom, sdk.NewInt(int64(params.TxGas)-1)))
testutil.FundModuleAccount(suite.app.BankKeeper, suite.ctx, authtypes.FeeCollectorName, coins)
}
queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, suite.app.EvmKeeper)
suite.queryClient = types.NewQueryClient(queryHelper)
@@ -150,7 +200,6 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
valAddr := sdk.ValAddress(suite.address.Bytes())
validator, err := stakingtypes.NewValidator(valAddr, priv.PubKey(), stakingtypes.Description{})
require.NoError(t, err)
err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator)
require.NoError(t, err)
err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator)
@@ -161,10 +210,7 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig)
suite.ethSigner = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
suite.appCodec = encodingConfig.Codec
}
func (suite *KeeperTestSuite) SetupTest() {
suite.DoSetupTest(suite.T())
suite.denom = evmtypes.DefaultEVMDenom
}
func (suite *KeeperTestSuite) EvmDenom() string {
@@ -381,17 +427,10 @@ func (suite *KeeperTestSuite) TestBaseFee() {
suite.app.EvmKeeper.BeginBlock(suite.ctx, abci.RequestBeginBlock{})
params := suite.app.EvmKeeper.GetParams(suite.ctx)
ethCfg := params.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID())
baseFee := suite.app.EvmKeeper.BaseFee(suite.ctx, ethCfg)
baseFee := suite.app.EvmKeeper.GetBaseFee(suite.ctx, ethCfg)
suite.Require().Equal(tc.expectBaseFee, baseFee)
})
}
suite.enableFeemarket = false
suite.enableLondonHF = true
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, &KeeperTestSuite{
enableFeemarket: false,
enableLondonHF: true,
})
}
+16
View File
@@ -1,5 +1,11 @@
package keeper
import (
v2 "github.com/cerc-io/laconicd/x/evm/migrations/v2"
v3 "github.com/cerc-io/laconicd/x/evm/migrations/v3"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Migrator is a struct for handling in-place store migrations.
type Migrator struct {
keeper Keeper
@@ -11,3 +17,13 @@ func NewMigrator(keeper Keeper) Migrator {
keeper: keeper,
}
}
// Migrate1to2 migrates the store from consensus version v1 to v2
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return v2.MigrateStore(ctx, &m.keeper.paramSpace)
}
// Migrate2to3 migrates the store from consensus version v2 to v3
func (m Migrator) Migrate2to3(ctx sdk.Context) error {
return v3.MigrateStore(ctx, &m.keeper.paramSpace)
}
+45 -1
View File
@@ -9,6 +9,8 @@ import (
tmbytes "github.com/tendermint/tendermint/libs/bytes"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/armon/go-metrics"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -19,7 +21,8 @@ var _ types.MsgServer = &Keeper{}
// EthereumTx implements the gRPC MsgServer interface. It receives a transaction which is then
// executed (i.e applied) against the go-ethereum EVM. The provided SDK Context is set to the Keeper
// so that it can call the StateDB methods without receiving it as a function parameter.
// so that it can implements and call the StateDB methods without receiving it as a function
// parameter.
func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*types.MsgEthereumTxResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
@@ -27,11 +30,52 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t
tx := msg.AsTransaction()
txIndex := k.GetTxIndexTransient(ctx)
labels := []metrics.Label{
telemetry.NewLabel("tx_type", fmt.Sprintf("%d", tx.Type())),
telemetry.NewLabel("from", sender),
}
if tx.To() == nil {
labels = []metrics.Label{telemetry.NewLabel("execution", "create")}
} else {
labels = []metrics.Label{
telemetry.NewLabel("execution", "call"),
telemetry.NewLabel("to", tx.To().Hex()), // recipient address (contract or account)
}
}
response, err := k.ApplyTransaction(ctx, tx)
if err != nil {
return nil, sdkerrors.Wrap(err, "failed to apply transaction")
}
defer func() {
telemetry.IncrCounterWithLabels(
[]string{"tx", "msg", "ethereum_tx", "total"},
1,
labels,
)
if response.GasUsed != 0 {
telemetry.IncrCounterWithLabels(
[]string{"tx", "msg", "ethereum_tx", "gas_used", "total"},
float32(response.GasUsed),
labels,
)
// Observe which users define a gas limit >> gas used. Note, that
// gas_limit and gas_used are always > 0
gasLimit := sdk.NewDec(int64(tx.Gas()))
gasRatio, err := gasLimit.QuoInt64(int64(response.GasUsed)).Float64()
if err == nil {
telemetry.SetGaugeWithLabels(
[]string{"tx", "msg", "ethereum_tx", "gas_limit", "per", "gas_used"},
float32(gasRatio),
labels,
)
}
}
}()
attrs := []sdk.Attribute{
sdk.NewAttribute(sdk.AttributeKeyAmount, tx.Value().String()),
// add event for ethereum transaction hash format
+6 -1
View File
@@ -8,7 +8,12 @@ import (
// GetParams returns the total set of evm parameters.
func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
k.paramSpace.GetParamSet(ctx, &params)
// TODO: update once https://github.com/cosmos/cosmos-sdk/pull/12615 is merged
// and released
for _, pair := range params.ParamSetPairs() {
k.paramSpace.GetIfExists(ctx, pair.Key, pair.Value)
}
return params
}
+91 -55
View File
@@ -4,6 +4,8 @@ import (
"math"
"math/big"
sdkmath "cosmossdk.io/math"
tmtypes "github.com/tendermint/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -14,6 +16,7 @@ import (
ethermint "github.com/cerc-io/laconicd/types"
"github.com/cerc-io/laconicd/x/evm/statedb"
"github.com/cerc-io/laconicd/x/evm/types"
evm "github.com/cerc-io/laconicd/x/evm/vm"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
@@ -46,7 +49,7 @@ func (k *Keeper) EVMConfig(ctx sdk.Context) (*types.EVMConfig, error) {
return nil, sdkerrors.Wrap(err, "failed to obtain coinbase address")
}
baseFee := k.BaseFee(ctx, ethCfg)
baseFee := k.GetBaseFee(ctx, ethCfg)
return &types.EVMConfig{
Params: params,
ChainConfig: ethCfg,
@@ -55,7 +58,7 @@ func (k *Keeper) EVMConfig(ctx sdk.Context) (*types.EVMConfig, error) {
}, nil
}
// TxConfig load `TxConfig` from current transient storage
// TxConfig loads `TxConfig` from current transient storage
func (k *Keeper) TxConfig(ctx sdk.Context, txHash common.Hash) statedb.TxConfig {
return statedb.NewTxConfig(
common.BytesToHash(ctx.HeaderHash()), // BlockHash
@@ -75,7 +78,7 @@ func (k *Keeper) NewEVM(
cfg *types.EVMConfig,
tracer vm.EVMLogger,
stateDB vm.StateDB,
) *vm.EVM {
) evm.EVM {
blockCtx := vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
@@ -93,7 +96,7 @@ func (k *Keeper) NewEVM(
tracer = k.Tracer(ctx, msg, cfg.ChainConfig)
}
vmConfig := k.VMConfig(ctx, msg, cfg, tracer)
return vm.NewEVM(blockCtx, txCtx, stateDB, cfg.ChainConfig, vmConfig)
return k.evmConstructor(blockCtx, txCtx, stateDB, cfg.ChainConfig, vmConfig, k.customPrecompiles)
}
// VMConfig creates an EVM configuration from the debug setting and the extra EIPs enabled on the
@@ -176,7 +179,7 @@ func (k Keeper) GetHashFn(ctx sdk.Context) vm.GetHashFunc {
// ApplyTransaction runs and attempts to perform a state transition with the given transaction (i.e Message), that will
// only be persisted (committed) to the underlying KVStore if the transaction does not fail.
//
// Gas tracking
// # Gas tracking
//
// Ethereum consumes gas according to the EVM opcodes instead of general reads and writes to store. Because of this, the
// state transition needs to ignore the SDK gas consumption mechanism defined by the GasKVStore and instead consume the
@@ -235,42 +238,47 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t
bloomReceipt = ethtypes.BytesToBloom(bloom.Bytes())
}
cumulativeGasUsed := res.GasUsed
if ctx.BlockGasMeter() != nil {
limit := ctx.BlockGasMeter().Limit()
consumed := ctx.BlockGasMeter().GasConsumed()
cumulativeGasUsed = uint64(math.Min(float64(cumulativeGasUsed+consumed), float64(limit)))
}
var contractAddr common.Address
if msg.To() == nil {
contractAddr = crypto.CreateAddress(msg.From(), msg.Nonce())
}
receipt := &ethtypes.Receipt{
Type: tx.Type(),
PostState: nil, // TODO: intermediate state root
CumulativeGasUsed: cumulativeGasUsed,
Bloom: bloomReceipt,
Logs: logs,
TxHash: txConfig.TxHash,
ContractAddress: contractAddr,
GasUsed: res.GasUsed,
BlockHash: txConfig.BlockHash,
BlockNumber: big.NewInt(ctx.BlockHeight()),
TransactionIndex: txConfig.TxIndex,
}
if !res.Failed() {
cumulativeGasUsed := res.GasUsed
if ctx.BlockGasMeter() != nil {
limit := ctx.BlockGasMeter().Limit()
consumed := ctx.BlockGasMeter().GasConsumed()
cumulativeGasUsed = uint64(math.Min(float64(cumulativeGasUsed+consumed), float64(limit)))
}
var contractAddr common.Address
if msg.To() == nil {
contractAddr = crypto.CreateAddress(msg.From(), msg.Nonce())
}
receipt := &ethtypes.Receipt{
Type: tx.Type(),
PostState: nil, // TODO: intermediate state root
Status: ethtypes.ReceiptStatusSuccessful,
CumulativeGasUsed: cumulativeGasUsed,
Bloom: bloomReceipt,
Logs: logs,
TxHash: txConfig.TxHash,
ContractAddress: contractAddr,
GasUsed: res.GasUsed,
BlockHash: txConfig.BlockHash,
BlockNumber: big.NewInt(ctx.BlockHeight()),
TransactionIndex: txConfig.TxIndex,
}
receipt.Status = ethtypes.ReceiptStatusSuccessful
// Only call hooks if tx executed successfully.
if err = k.PostTxProcessing(tmpCtx, msg.From(), tx.To(), receipt); err != nil {
if err = k.PostTxProcessing(tmpCtx, msg, receipt); err != nil {
// If hooks return error, revert the whole tx.
res.VmError = types.ErrPostTxProcessing.Error()
k.Logger(ctx).Error("tx post processing failed", "error", err)
// If the tx failed in post processing hooks, we should clear the logs
res.Logs = nil
} else if commit != nil {
// PostTxProcessing is successful, commit the tmpCtx
commit()
// Since the post processing can alter the log, we need to update the result
res.Logs = types.NewLogsFromEth(receipt.Logs)
ctx.EventManager().EmitEvents(tmpCtx.EventManager().Events())
}
}
@@ -280,11 +288,10 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t
return nil, sdkerrors.Wrapf(err, "failed to refund gas leftover gas to sender %s", msg.From())
}
if len(logs) > 0 {
if len(receipt.Logs) > 0 {
// Update transient block bloom filter
k.SetBlockBloomTransient(ctx, bloom)
k.SetLogSizeTransient(ctx, uint64(txConfig.LogIndex)+uint64(len(logs)))
k.SetBlockBloomTransient(ctx, receipt.Bloom.Big())
k.SetLogSizeTransient(ctx, uint64(txConfig.LogIndex)+uint64(len(receipt.Logs)))
}
k.SetTxIndexTransient(ctx, uint64(txConfig.TxIndex)+1)
@@ -303,18 +310,18 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t
// If the message fails, the VM execution error with the reason will be returned to the client
// and the transaction won't be committed to the store.
//
// Reverted state
// # Reverted state
//
// The snapshot and rollback are supported by the `statedb.StateDB`.
//
// Different Callers
// # Different Callers
//
// It's called in three scenarios:
// 1. `ApplyTransaction`, in the transaction processing flow.
// 2. `EthCall/EthEstimateGas` grpc query handler.
// 3. Called by other native modules directly.
//
// Prechecks and Preprocessing
// # Prechecks and Preprocessing
//
// All relevant state transition prechecks for the MsgEthereumTx are performed on the AnteHandler,
// prior to running the transaction against the state. The prechecks run are the following:
@@ -330,14 +337,20 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t
//
// 1. set up the initial access list (iff fork > Berlin)
//
// Tracer parameter
// # Tracer parameter
//
// It should be a `vm.Tracer` object or nil, if pass `nil`, it'll create a default one based on keeper options.
//
// Commit parameter
// # Commit parameter
//
// If commit is true, the `StateDB` will be committed, otherwise discarded.
func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, msg core.Message, tracer vm.EVMLogger, commit bool, cfg *types.EVMConfig, txConfig statedb.TxConfig) (*types.MsgEthereumTxResponse, error) {
func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context,
msg core.Message,
tracer vm.EVMLogger,
commit bool,
cfg *types.EVMConfig,
txConfig statedb.TxConfig,
) (*types.MsgEthereumTxResponse, error) {
var (
ret []byte // return bytes from evm execution
vmErr error // vm errors do not effect consensus and are therefore not assigned to err
@@ -353,26 +366,38 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, msg core.Message, trace
stateDB := statedb.New(ctx, k, txConfig)
evm := k.NewEVM(ctx, msg, cfg, tracer, stateDB)
leftoverGas := msg.Gas()
// Allow the tracer captures the tx level events, mainly the gas consumption.
vmCfg := evm.Config()
if vmCfg.Debug {
vmCfg.Tracer.CaptureTxStart(leftoverGas)
defer func() {
vmCfg.Tracer.CaptureTxEnd(leftoverGas)
}()
}
sender := vm.AccountRef(msg.From())
contractCreation := msg.To() == nil
isLondon := cfg.ChainConfig.IsLondon(evm.Context.BlockNumber)
isLondon := cfg.ChainConfig.IsLondon(evm.Context().BlockNumber)
intrinsicGas, err := k.GetEthIntrinsicGas(ctx, msg, cfg.ChainConfig, contractCreation)
if err != nil {
// should have already been checked on Ante Handler
return nil, sdkerrors.Wrap(err, "intrinsic gas failed")
}
// Should check again even if it is checked on Ante Handler, because eth_call don't go through Ante Handler.
if msg.Gas() < intrinsicGas {
if leftoverGas < intrinsicGas {
// eth_estimateGas will check for this exact error
return nil, sdkerrors.Wrap(core.ErrIntrinsicGas, "apply message")
}
leftoverGas := msg.Gas() - intrinsicGas
leftoverGas -= intrinsicGas
// access list preparation is moved from ante handler to here, because it's needed when `ApplyMessage` is called
// under contexts where ante handlers are not run, for example `eth_call` and `eth_estimateGas`.
if rules := cfg.ChainConfig.Rules(big.NewInt(ctx.BlockHeight()), cfg.ChainConfig.MergeForkBlock != nil); rules.IsBerlin {
stateDB.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
if rules := cfg.ChainConfig.Rules(big.NewInt(ctx.BlockHeight()), cfg.ChainConfig.MergeNetsplitBlock != nil); rules.IsBerlin {
stateDB.PrepareAccessList(msg.From(), msg.To(), evm.ActivePrecompiles(rules), msg.AccessList())
}
if contractCreation {
@@ -397,12 +422,8 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, msg core.Message, trace
if msg.Gas() < leftoverGas {
return nil, sdkerrors.Wrap(types.ErrGasOverflow, "apply message")
}
gasUsed := msg.Gas() - leftoverGas
refund := GasToRefund(stateDB.GetRefund(), gasUsed, refundQuotient)
if refund > gasUsed {
return nil, sdkerrors.Wrap(types.ErrGasOverflow, "apply message")
}
gasUsed -= refund
// refund gas
leftoverGas += GasToRefund(stateDB.GetRefund(), msg.Gas()-leftoverGas, refundQuotient)
// EVM execution error needs to be available for the JSON-RPC client
var vmError string
@@ -417,6 +438,21 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, msg core.Message, trace
}
}
// calculate a minimum amount of gas to be charged to sender if GasLimit
// is considerably higher than GasUsed to stay more aligned with Tendermint gas mechanics
// for more info https://github.com/cerc-io/laconicd/issues/1085
gasLimit := sdk.NewDec(int64(msg.Gas()))
minGasMultiplier := k.GetMinGasMultiplier(ctx)
minimumGasUsed := gasLimit.Mul(minGasMultiplier)
if msg.Gas() < leftoverGas {
return nil, sdkerrors.Wrapf(types.ErrGasOverflow, "message gas limit < leftover gas (%d < %d)", msg.Gas(), leftoverGas)
}
temporaryGasUsed := msg.Gas() - leftoverGas
gasUsed := sdk.MaxDec(minimumGasUsed, sdk.NewDec(int64(temporaryGasUsed))).TruncateInt().Uint64()
// reset leftoverGas, to be used by the tracer
leftoverGas = msg.Gas() - gasUsed
return &types.MsgEthereumTxResponse{
GasUsed: gasUsed,
VmError: vmError,
@@ -459,7 +495,7 @@ func (k *Keeper) RefundGas(ctx sdk.Context, msg core.Message, leftoverGas uint64
return sdkerrors.Wrapf(types.ErrInvalidRefund, "refunded amount value cannot be negative %d", remaining.Int64())
case 1:
// positive amount refund
refundedCoins := sdk.Coins{sdk.NewCoin(denom, sdk.NewIntFromBigInt(remaining))}
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
@@ -143,7 +143,7 @@ func newNativeMessage(
func BenchmarkApplyTransaction(b *testing.B) {
suite := KeeperTestSuite{enableLondonHF: true}
suite.DoSetupTest(b)
suite.SetupTest()
ethSigner := ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
@@ -170,7 +170,7 @@ func BenchmarkApplyTransaction(b *testing.B) {
func BenchmarkApplyTransactionWithLegacyTx(b *testing.B) {
suite := KeeperTestSuite{enableLondonHF: true}
suite.DoSetupTest(b)
suite.SetupTest()
ethSigner := ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
@@ -197,7 +197,7 @@ func BenchmarkApplyTransactionWithLegacyTx(b *testing.B) {
func BenchmarkApplyTransactionWithDynamicFeeTx(b *testing.B) {
suite := KeeperTestSuite{enableFeemarket: true, enableLondonHF: true}
suite.DoSetupTest(b)
suite.SetupTest()
ethSigner := ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
@@ -224,7 +224,7 @@ func BenchmarkApplyTransactionWithDynamicFeeTx(b *testing.B) {
func BenchmarkApplyMessage(b *testing.B) {
suite := KeeperTestSuite{enableLondonHF: true}
suite.DoSetupTest(b)
suite.SetupTest()
params := suite.app.EvmKeeper.GetParams(suite.ctx)
ethCfg := params.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID())
@@ -259,7 +259,7 @@ func BenchmarkApplyMessage(b *testing.B) {
func BenchmarkApplyMessageWithLegacyTx(b *testing.B) {
suite := KeeperTestSuite{enableLondonHF: true}
suite.DoSetupTest(b)
suite.SetupTest()
params := suite.app.EvmKeeper.GetParams(suite.ctx)
ethCfg := params.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID())
@@ -294,7 +294,7 @@ func BenchmarkApplyMessageWithLegacyTx(b *testing.B) {
func BenchmarkApplyMessageWithDynamicFeeTx(b *testing.B) {
suite := KeeperTestSuite{enableFeemarket: true, enableLondonHF: true}
suite.DoSetupTest(b)
suite.SetupTest()
params := suite.app.EvmKeeper.GetParams(suite.ctx)
ethCfg := params.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID())
-10
View File
@@ -206,16 +206,6 @@ func (suite *KeeperTestSuite) TestGetEthIntrinsicGas() {
true,
params.TxGas + params.TxDataNonZeroGasFrontier*1,
},
// we are not able to test the ErrGasUintOverflow due to RAM limitation
// {
// "with big data size overflow",
// make([]byte, 271300000000000000),
// nil,
// 1,
// false,
// false,
// 0,
// },
{
"no data, one accesslist, not contract creation, not homestead, not istanbul",
nil,
+5 -10
View File
@@ -1,10 +1,11 @@
package keeper
import (
"bytes"
"fmt"
"math/big"
sdkmath "cosmossdk.io/math"
ethermint "github.com/cerc-io/laconicd/types"
"github.com/cerc-io/laconicd/x/evm/statedb"
"github.com/cerc-io/laconicd/x/evm/types"
@@ -79,7 +80,7 @@ func (k *Keeper) SetBalance(ctx sdk.Context, addr common.Address, amount *big.In
switch delta.Sign() {
case 1:
// mint
coins := sdk.NewCoins(sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(delta)))
coins := sdk.NewCoins(sdk.NewCoin(params.EvmDenom, sdkmath.NewIntFromBigInt(delta)))
if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil {
return err
}
@@ -88,7 +89,7 @@ func (k *Keeper) SetBalance(ctx sdk.Context, addr common.Address, amount *big.In
}
case -1:
// burn
coins := sdk.NewCoins(sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(new(big.Int).Neg(delta))))
coins := sdk.NewCoins(sdk.NewCoin(params.EvmDenom, sdkmath.NewIntFromBigInt(new(big.Int).Neg(delta))))
if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, cosmosAddr, types.ModuleName, coins); err != nil {
return err
}
@@ -186,7 +187,7 @@ func (k *Keeper) DeleteAccount(ctx sdk.Context, addr common.Address) error {
}
// NOTE: only Ethereum accounts (contracts) can be selfdestructed
ethAcct, ok := acct.(ethermint.EthAccountI)
_, ok := acct.(ethermint.EthAccountI)
if !ok {
return sdkerrors.Wrapf(types.ErrInvalidAccount, "type %T, address %s", acct, addr)
}
@@ -196,12 +197,6 @@ func (k *Keeper) DeleteAccount(ctx sdk.Context, addr common.Address) error {
return err
}
// remove code
codeHashBz := ethAcct.GetCodeHash().Bytes()
if !bytes.Equal(codeHashBz, types.EmptyCodeHash) {
k.SetCode(ctx, codeHashBz, nil)
}
// clear storage
k.ForEachStorage(ctx, addr, func(key, _ common.Hash) bool {
k.SetState(ctx, addr, key, nil)
+11 -11
View File
@@ -15,7 +15,7 @@ import (
func BenchmarkCreateAccountNew(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
b.ResetTimer()
@@ -31,7 +31,7 @@ func BenchmarkCreateAccountNew(b *testing.B) {
func BenchmarkCreateAccountExisting(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
b.ResetTimer()
@@ -44,7 +44,7 @@ func BenchmarkCreateAccountExisting(b *testing.B) {
func BenchmarkAddBalance(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
amt := big.NewInt(10)
@@ -59,7 +59,7 @@ func BenchmarkAddBalance(b *testing.B) {
func BenchmarkSetCode(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
hash := crypto.Keccak256Hash([]byte("code")).Bytes()
@@ -74,7 +74,7 @@ func BenchmarkSetCode(b *testing.B) {
func BenchmarkSetState(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
hash := crypto.Keccak256Hash([]byte("topic")).Bytes()
@@ -89,7 +89,7 @@ func BenchmarkSetState(b *testing.B) {
func BenchmarkAddLog(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
topic := crypto.Keccak256Hash([]byte("topic"))
@@ -116,7 +116,7 @@ func BenchmarkAddLog(b *testing.B) {
func BenchmarkSnapshot(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
b.ResetTimer()
@@ -136,7 +136,7 @@ func BenchmarkSnapshot(b *testing.B) {
func BenchmarkSubBalance(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
amt := big.NewInt(10)
@@ -151,7 +151,7 @@ func BenchmarkSubBalance(b *testing.B) {
func BenchmarkSetNonce(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
b.ResetTimer()
@@ -164,7 +164,7 @@ func BenchmarkSetNonce(b *testing.B) {
func BenchmarkAddRefund(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
b.ResetTimer()
@@ -177,7 +177,7 @@ func BenchmarkAddRefund(b *testing.B) {
func BenchmarkSuicide(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
b.ResetTimer()
+19
View File
@@ -11,6 +11,7 @@ import (
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
"github.com/cerc-io/laconicd/tests"
"github.com/cerc-io/laconicd/x/evm/statedb"
"github.com/cerc-io/laconicd/x/evm/types"
@@ -420,12 +421,26 @@ func (suite *KeeperTestSuite) TestSuicide() {
suite.Require().NoError(db.Commit())
db = suite.StateDB()
// Generate 2nd address
privkey, _ := ethsecp256k1.GenerateKey()
key, err := privkey.ToECDSA()
suite.Require().NoError(err)
addr2 := crypto.PubkeyToAddress(key.PublicKey)
// Add code and state to account 2
db.SetCode(addr2, code)
suite.Require().Equal(code, db.GetCode(addr2))
for i := 0; i < 5; i++ {
db.SetState(addr2, common.BytesToHash([]byte(fmt.Sprintf("key%d", i))), common.BytesToHash([]byte(fmt.Sprintf("value%d", i))))
}
// Call Suicide
suite.Require().Equal(true, db.Suicide(suite.address))
// Check suicided is marked
suite.Require().Equal(true, db.HasSuicided(suite.address))
// Commit state
suite.Require().NoError(db.Commit())
db = suite.StateDB()
@@ -441,6 +456,10 @@ func (suite *KeeperTestSuite) TestSuicide() {
// Check account is deleted
suite.Require().Equal(common.Hash{}, db.GetCodeHash(suite.address))
// Check code is still present in addr2 and suicided is false
suite.Require().NotNil(db.GetCode(addr2))
suite.Require().Equal(false, db.HasSuicided(addr2))
}
func (suite *KeeperTestSuite) TestExist() {
+36 -22
View File
@@ -1,12 +1,13 @@
package keeper
import (
"math"
"math/big"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
ante "github.com/cosmos/cosmos-sdk/x/auth/ante"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
@@ -15,19 +16,20 @@ import (
)
// DeductTxCostsFromUserBalance it calculates the tx costs and deducts the fees
// returns (effectiveFee, priority, error)
func (k Keeper) DeductTxCostsFromUserBalance(
ctx sdk.Context,
msgEthTx evmtypes.MsgEthereumTx,
txData evmtypes.TxData,
denom string,
homestead, istanbul, london bool,
) (sdk.Coins, error) {
) (fees sdk.Coins, priority int64, err error) {
isContractCreation := txData.GetTo() == nil
// fetch sender account from signature
signerAcc, err := ante.GetSignerAcc(ctx, k.accountKeeper, msgEthTx.GetFrom())
signerAcc, err := authante.GetSignerAcc(ctx, k.accountKeeper, msgEthTx.GetFrom())
if err != nil {
return nil, sdkerrors.Wrapf(err, "account not found for sender %s", msgEthTx.From)
return nil, 0, sdkerrors.Wrapf(err, "account not found for sender %s", msgEthTx.From)
}
gasLimit := txData.GetGas()
@@ -39,7 +41,7 @@ func (k Keeper) DeductTxCostsFromUserBalance(
intrinsicGas, err := core.IntrinsicGas(txData.GetData(), accessList, isContractCreation, homestead, istanbul)
if err != nil {
return nil, sdkerrors.Wrapf(
return nil, 0, sdkerrors.Wrapf(
err,
"failed to retrieve intrinsic gas, contract creation = %t; homestead = %t, istanbul = %t",
isContractCreation, homestead, istanbul,
@@ -48,7 +50,7 @@ func (k Keeper) DeductTxCostsFromUserBalance(
// intrinsic gas verification during CheckTx
if ctx.IsCheckTx() && gasLimit < intrinsicGas {
return nil, sdkerrors.Wrapf(
return nil, 0, sdkerrors.Wrapf(
sdkerrors.ErrOutOfGas,
"gas limit too low: %d (gas limit) < %d (intrinsic gas)", gasLimit, intrinsicGas,
)
@@ -56,39 +58,51 @@ func (k Keeper) DeductTxCostsFromUserBalance(
var feeAmt *big.Int
feeMktParams := k.feeMarketKeeper.GetParams(ctx)
if london && !feeMktParams.NoBaseFee && txData.TxType() == ethtypes.DynamicFeeTxType {
baseFee := k.feeMarketKeeper.GetBaseFee(ctx)
if txData.GetGasFeeCap().Cmp(baseFee) < 0 {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "the tx gasfeecap is lower than the tx baseFee: %s (gasfeecap), %s (basefee) ", txData.GetGasFeeCap(), baseFee)
}
feeAmt = txData.EffectiveFee(baseFee)
} else {
feeAmt = txData.Fee()
baseFee := k.getBaseFee(ctx, london)
if baseFee != nil && txData.GetGasFeeCap().Cmp(baseFee) < 0 {
return nil, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee,
"the tx gasfeecap is lower than the tx baseFee: %s (gasfeecap), %s (basefee) ",
txData.GetGasFeeCap(),
baseFee)
}
feeAmt = txData.EffectiveFee(baseFee)
if feeAmt.Sign() == 0 {
// zero fee, no need to deduct
return sdk.NewCoins(), nil
return sdk.Coins{}, 0, nil
}
fees := sdk.Coins{sdk.NewCoin(denom, sdk.NewIntFromBigInt(feeAmt))}
fees = sdk.Coins{sdk.NewCoin(denom, sdkmath.NewIntFromBigInt(feeAmt))}
// deduct the full gas cost from the user balance
if err := ante.DeductFees(k.bankKeeper, ctx, signerAcc, fees); err != nil {
return nil, sdkerrors.Wrapf(
if err := authante.DeductFees(k.bankKeeper, ctx, signerAcc, fees); err != nil {
return nil, 0, sdkerrors.Wrapf(
err,
"failed to deduct full gas cost %s from the user %s balance",
fees, msgEthTx.From,
)
}
return fees, nil
// calculate priority based on effective gas price
tipPrice := txData.EffectiveGasPrice(baseFee)
// if london hardfork is not enabled, tipPrice is the gasPrice
if baseFee != nil {
tipPrice = new(big.Int).Sub(tipPrice, baseFee)
}
priorityBig := new(big.Int).Quo(tipPrice, evmtypes.DefaultPriorityReduction.BigInt())
if !priorityBig.IsInt64() {
priority = math.MaxInt64
} else {
priority = priorityBig.Int64()
}
return fees, priority, nil
}
// CheckSenderBalance validates that the tx cost value is positive and that the
// sender has enough funds to pay for the fees and value of the transaction.
func CheckSenderBalance(
balance sdk.Int,
balance sdkmath.Int,
txData evmtypes.TxData,
) error {
cost := txData.Cost()
+19 -17
View File
@@ -3,6 +3,7 @@ package keeper_test
import (
"math/big"
sdkmath "cosmossdk.io/math"
evmkeeper "github.com/cerc-io/laconicd/x/evm/keeper"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -12,21 +13,21 @@ import (
)
func (suite *KeeperTestSuite) TestCheckSenderBalance() {
hundredInt := sdk.NewInt(100)
hundredInt := sdkmath.NewInt(100)
zeroInt := sdk.ZeroInt()
oneInt := sdk.OneInt()
fiveInt := sdk.NewInt(5)
fiftyInt := sdk.NewInt(50)
negInt := sdk.NewInt(-10)
fiveInt := sdkmath.NewInt(5)
fiftyInt := sdkmath.NewInt(50)
negInt := sdkmath.NewInt(-10)
testCases := []struct {
name string
to string
gasLimit uint64
gasPrice *sdk.Int
gasPrice *sdkmath.Int
gasFeeCap *big.Int
gasTipCap *big.Int
cost *sdk.Int
cost *sdkmath.Int
from string
accessList *ethtypes.AccessList
expectPass bool
@@ -237,7 +238,7 @@ func (suite *KeeperTestSuite) TestCheckSenderBalance() {
acct := suite.app.EvmKeeper.GetAccountOrEmpty(suite.ctx, suite.address)
err := evmkeeper.CheckSenderBalance(
sdk.NewIntFromBigInt(acct.Balance),
sdkmath.NewIntFromBigInt(acct.Balance),
txData,
)
@@ -251,22 +252,22 @@ func (suite *KeeperTestSuite) TestCheckSenderBalance() {
}
func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
hundredInt := sdk.NewInt(100)
hundredInt := sdkmath.NewInt(100)
zeroInt := sdk.ZeroInt()
oneInt := sdk.NewInt(1)
fiveInt := sdk.NewInt(5)
fiftyInt := sdk.NewInt(50)
oneInt := sdkmath.NewInt(1)
fiveInt := sdkmath.NewInt(5)
fiftyInt := sdkmath.NewInt(50)
// should be enough to cover all test cases
initBalance := sdk.NewInt((ethparams.InitialBaseFee + 10) * 105)
initBalance := sdkmath.NewInt((ethparams.InitialBaseFee + 10) * 105)
testCases := []struct {
name string
gasLimit uint64
gasPrice *sdk.Int
gasPrice *sdkmath.Int
gasFeeCap *big.Int
gasTipCap *big.Int
cost *sdk.Int
cost *sdkmath.Int
accessList *ethtypes.AccessList
expectPass bool
enableFeemarket bool
@@ -402,7 +403,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
txData, _ := evmtypes.UnpackTxData(tx.Data)
fees, err := suite.app.EvmKeeper.DeductTxCostsFromUserBalance(
fees, priority, err := suite.app.EvmKeeper.DeductTxCostsFromUserBalance(
suite.ctx,
*tx,
txData,
@@ -419,15 +420,16 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
suite.Require().Equal(
fees,
sdk.NewCoins(
sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewIntFromBigInt(txData.EffectiveFee(baseFee))),
sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewIntFromBigInt(txData.EffectiveFee(baseFee))),
),
"valid test %d failed, fee value is wrong ", i,
)
suite.Require().Equal(int64(0), priority)
} else {
suite.Require().Equal(
fees,
sdk.NewCoins(
sdk.NewCoin(evmtypes.DefaultEVMDenom, tc.gasPrice.Mul(sdk.NewIntFromUint64(tc.gasLimit))),
sdk.NewCoin(evmtypes.DefaultEVMDenom, tc.gasPrice.Mul(sdkmath.NewIntFromUint64(tc.gasLimit))),
),
"valid test %d failed, fee value is wrong ", i,
)
+19
View File
@@ -0,0 +1,19 @@
package v2
import (
"github.com/cerc-io/laconicd/x/evm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
)
// MigrateStore sets the default AllowUnprotectedTxs parameter.
func MigrateStore(ctx sdk.Context, paramstore *paramtypes.Subspace) error {
if !paramstore.HasKeyTable() {
ps := paramstore.WithKeyTable(types.ParamKeyTable())
paramstore = &ps
}
// add RejectUnprotected
paramstore.Set(ctx, types.ParamStoreKeyAllowUnprotectedTxs, types.DefaultAllowUnprotectedTxs)
return nil
}
+47
View File
@@ -0,0 +1,47 @@
package v2_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/cerc-io/laconicd/encoding"
"github.com/cerc-io/laconicd/app"
v2 "github.com/cerc-io/laconicd/x/evm/migrations/v2"
v2types "github.com/cerc-io/laconicd/x/evm/migrations/v2/types"
"github.com/cerc-io/laconicd/x/evm/types"
)
func TestMigrateStore(t *testing.T) {
encCfg := encoding.MakeConfig(app.ModuleBasics)
feemarketKey := sdk.NewKVStoreKey(types.StoreKey)
tFeeMarketKey := sdk.NewTransientStoreKey(fmt.Sprintf("%s_test", types.StoreKey))
ctx := testutil.DefaultContext(feemarketKey, tFeeMarketKey)
paramstore := paramtypes.NewSubspace(
encCfg.Codec, encCfg.Amino, feemarketKey, tFeeMarketKey, "evm",
).WithKeyTable(v2types.ParamKeyTable())
params := v2types.DefaultParams()
paramstore.SetParamSet(ctx, &params)
require.Panics(t, func() {
var result bool
paramstore.Get(ctx, types.ParamStoreKeyAllowUnprotectedTxs, &result)
})
paramstore = paramtypes.NewSubspace(
encCfg.Codec, encCfg.Amino, feemarketKey, tFeeMarketKey, "evm",
).WithKeyTable(types.ParamKeyTable())
err := v2.MigrateStore(ctx, &paramstore)
require.NoError(t, err)
var result bool
paramstore.Get(ctx, types.ParamStoreKeyAllowUnprotectedTxs, &result)
require.Equal(t, types.DefaultAllowUnprotectedTxs, result)
}
+167
View File
@@ -0,0 +1,167 @@
package types
import (
"math/big"
"strings"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params"
"github.com/cerc-io/laconicd/x/evm/types"
)
// EthereumConfig returns an Ethereum ChainConfig for EVM state transitions.
// All the negative or nil values are converted to nil
func (cc ChainConfig) EthereumConfig(chainID *big.Int) *params.ChainConfig {
return &params.ChainConfig{
ChainID: chainID,
HomesteadBlock: getBlockValue(cc.HomesteadBlock),
DAOForkBlock: getBlockValue(cc.DAOForkBlock),
DAOForkSupport: cc.DAOForkSupport,
EIP150Block: getBlockValue(cc.EIP150Block),
EIP150Hash: common.HexToHash(cc.EIP150Hash),
EIP155Block: getBlockValue(cc.EIP155Block),
EIP158Block: getBlockValue(cc.EIP158Block),
ByzantiumBlock: getBlockValue(cc.ByzantiumBlock),
ConstantinopleBlock: getBlockValue(cc.ConstantinopleBlock),
PetersburgBlock: getBlockValue(cc.PetersburgBlock),
IstanbulBlock: getBlockValue(cc.IstanbulBlock),
MuirGlacierBlock: getBlockValue(cc.MuirGlacierBlock),
BerlinBlock: getBlockValue(cc.BerlinBlock),
LondonBlock: getBlockValue(cc.LondonBlock),
ArrowGlacierBlock: getBlockValue(cc.ArrowGlacierBlock),
MergeNetsplitBlock: getBlockValue(cc.MergeForkBlock),
TerminalTotalDifficulty: nil,
Ethash: nil,
Clique: nil,
}
}
// DefaultChainConfig returns default evm parameters.
func DefaultChainConfig() ChainConfig {
homesteadBlock := sdk.ZeroInt()
daoForkBlock := sdk.ZeroInt()
eip150Block := sdk.ZeroInt()
eip155Block := sdk.ZeroInt()
eip158Block := sdk.ZeroInt()
byzantiumBlock := sdk.ZeroInt()
constantinopleBlock := sdk.ZeroInt()
petersburgBlock := sdk.ZeroInt()
istanbulBlock := sdk.ZeroInt()
muirGlacierBlock := sdk.ZeroInt()
berlinBlock := sdk.ZeroInt()
londonBlock := sdk.ZeroInt()
arrowGlacierBlock := sdk.ZeroInt()
mergeForkBlock := sdk.ZeroInt()
return ChainConfig{
HomesteadBlock: &homesteadBlock,
DAOForkBlock: &daoForkBlock,
DAOForkSupport: true,
EIP150Block: &eip150Block,
EIP150Hash: common.Hash{}.String(),
EIP155Block: &eip155Block,
EIP158Block: &eip158Block,
ByzantiumBlock: &byzantiumBlock,
ConstantinopleBlock: &constantinopleBlock,
PetersburgBlock: &petersburgBlock,
IstanbulBlock: &istanbulBlock,
MuirGlacierBlock: &muirGlacierBlock,
BerlinBlock: &berlinBlock,
LondonBlock: &londonBlock,
ArrowGlacierBlock: &arrowGlacierBlock,
MergeForkBlock: &mergeForkBlock,
}
}
func getBlockValue(block *sdkmath.Int) *big.Int {
if block == nil || block.IsNegative() {
return nil
}
return block.BigInt()
}
// Validate performs a basic validation of the ChainConfig params. The function will return an error
// if any of the block values is uninitialized (i.e nil) or if the EIP150Hash is an invalid hash.
func (cc ChainConfig) Validate() error {
if err := validateBlock(cc.HomesteadBlock); err != nil {
return sdkerrors.Wrap(err, "homesteadBlock")
}
if err := validateBlock(cc.DAOForkBlock); err != nil {
return sdkerrors.Wrap(err, "daoForkBlock")
}
if err := validateBlock(cc.EIP150Block); err != nil {
return sdkerrors.Wrap(err, "eip150Block")
}
if err := validateHash(cc.EIP150Hash); err != nil {
return err
}
if err := validateBlock(cc.EIP155Block); err != nil {
return sdkerrors.Wrap(err, "eip155Block")
}
if err := validateBlock(cc.EIP158Block); err != nil {
return sdkerrors.Wrap(err, "eip158Block")
}
if err := validateBlock(cc.ByzantiumBlock); err != nil {
return sdkerrors.Wrap(err, "byzantiumBlock")
}
if err := validateBlock(cc.ConstantinopleBlock); err != nil {
return sdkerrors.Wrap(err, "constantinopleBlock")
}
if err := validateBlock(cc.PetersburgBlock); err != nil {
return sdkerrors.Wrap(err, "petersburgBlock")
}
if err := validateBlock(cc.IstanbulBlock); err != nil {
return sdkerrors.Wrap(err, "istanbulBlock")
}
if err := validateBlock(cc.MuirGlacierBlock); err != nil {
return sdkerrors.Wrap(err, "muirGlacierBlock")
}
if err := validateBlock(cc.BerlinBlock); err != nil {
return sdkerrors.Wrap(err, "berlinBlock")
}
if err := validateBlock(cc.LondonBlock); err != nil {
return sdkerrors.Wrap(err, "londonBlock")
}
if err := validateBlock(cc.ArrowGlacierBlock); err != nil {
return sdkerrors.Wrap(err, "arrowGlacierBlock")
}
if err := validateBlock(cc.MergeForkBlock); err != nil {
return sdkerrors.Wrap(err, "mergeForkBlock")
}
// NOTE: chain ID is not needed to check config order
if err := cc.EthereumConfig(nil).CheckConfigForkOrder(); err != nil {
return sdkerrors.Wrap(err, "invalid config fork order")
}
return nil
}
func validateHash(hex string) error {
if hex != "" && strings.TrimSpace(hex) == "" {
return sdkerrors.Wrap(types.ErrInvalidChainConfig, "hash cannot be blank")
}
return nil
}
func validateBlock(block *sdkmath.Int) error {
// nil value means that the fork has not yet been applied
if block == nil {
return nil
}
if block.IsNegative() {
return sdkerrors.Wrapf(
types.ErrInvalidChainConfig, "block value cannot be negative: %s", block,
)
}
return nil
}
+3781
View File
File diff suppressed because it is too large Load Diff
+145
View File
@@ -0,0 +1,145 @@
package types
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/params"
"github.com/cerc-io/laconicd/types"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/ethereum/go-ethereum/core/vm"
)
var _ paramtypes.ParamSet = &Params{}
const (
DefaultEVMDenom = types.AttoPhoton
)
// DefaultMinGasMultiplier is 0.5 or 50%
var DefaultMinGasMultiplier = sdk.NewDecWithPrec(50, 2)
// Parameter keys
var (
ParamStoreKeyEVMDenom = []byte("EVMDenom")
ParamStoreKeyEnableCreate = []byte("EnableCreate")
ParamStoreKeyEnableCall = []byte("EnableCall")
ParamStoreKeyExtraEIPs = []byte("EnableExtraEIPs")
ParamStoreKeyChainConfig = []byte("ChainConfig")
// AvailableExtraEIPs define the list of all EIPs that can be enabled by the
// EVM interpreter. These EIPs are applied in order and can override the
// instruction sets from the latest hard fork enabled by the ChainConfig. For
// more info check:
// https://github.com/ethereum/go-ethereum/blob/master/core/vm/interpreter.go#L97
AvailableExtraEIPs = []int64{1344, 1884, 2200, 2929, 3198, 3529}
)
// ParamKeyTable returns the parameter key table.
func ParamKeyTable() paramtypes.KeyTable {
return paramtypes.NewKeyTable().RegisterParamSet(&Params{})
}
// NewParams creates a new Params instance
func NewParams(evmDenom string, enableCreate, enableCall bool, config ChainConfig, extraEIPs ...int64) Params {
return Params{
EvmDenom: evmDenom,
EnableCreate: enableCreate,
EnableCall: enableCall,
ExtraEIPs: extraEIPs,
ChainConfig: config,
}
}
// DefaultParams returns default evm parameters
// ExtraEIPs is empty to prevent overriding the latest hard fork instruction set
func DefaultParams() Params {
return Params{
EvmDenom: DefaultEVMDenom,
EnableCreate: true,
EnableCall: true,
ChainConfig: DefaultChainConfig(),
ExtraEIPs: nil,
}
}
// ParamSetPairs returns the parameter set pairs.
func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
return paramtypes.ParamSetPairs{
paramtypes.NewParamSetPair(ParamStoreKeyEVMDenom, &p.EvmDenom, validateEVMDenom),
paramtypes.NewParamSetPair(ParamStoreKeyEnableCreate, &p.EnableCreate, validateBool),
paramtypes.NewParamSetPair(ParamStoreKeyEnableCall, &p.EnableCall, validateBool),
paramtypes.NewParamSetPair(ParamStoreKeyExtraEIPs, &p.ExtraEIPs, validateEIPs),
paramtypes.NewParamSetPair(ParamStoreKeyChainConfig, &p.ChainConfig, validateChainConfig),
}
}
// Validate performs basic validation on evm parameters.
func (p Params) Validate() error {
if err := sdk.ValidateDenom(p.EvmDenom); err != nil {
return err
}
if err := validateEIPs(p.ExtraEIPs); err != nil {
return err
}
return p.ChainConfig.Validate()
}
// EIPs returns the ExtraEips as a int slice
func (p Params) EIPs() []int {
eips := make([]int, len(p.ExtraEIPs))
for i, eip := range p.ExtraEIPs {
eips[i] = int(eip)
}
return eips
}
func validateEVMDenom(i interface{}) error {
denom, ok := i.(string)
if !ok {
return fmt.Errorf("invalid parameter EVM denom type: %T", i)
}
return sdk.ValidateDenom(denom)
}
func validateBool(i interface{}) error {
_, ok := i.(bool)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
return nil
}
func validateEIPs(i interface{}) error {
eips, ok := i.([]int64)
if !ok {
return fmt.Errorf("invalid EIP slice type: %T", i)
}
for _, eip := range eips {
if !vm.ValidEip(int(eip)) {
return fmt.Errorf("EIP %d is not activateable, valid EIPS are: %s", eip, vm.ActivateableEips())
}
}
return nil
}
func validateChainConfig(i interface{}) error {
cfg, ok := i.(ChainConfig)
if !ok {
return fmt.Errorf("invalid chain config type: %T", i)
}
return cfg.Validate()
}
// IsLondon returns if london hardfork is enabled.
func IsLondon(ethConfig *params.ChainConfig, height int64) bool {
return ethConfig.IsLondon(big.NewInt(height))
}
+25
View File
@@ -0,0 +1,25 @@
package v3
import (
"github.com/cerc-io/laconicd/x/evm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
)
// MigrateStore sets the default for GrayGlacierBlock and MergeNetsplitBlock in ChainConfig parameter.
func MigrateStore(ctx sdk.Context, paramstore *paramtypes.Subspace) error {
if !paramstore.HasKeyTable() {
ps := paramstore.WithKeyTable(types.ParamKeyTable())
paramstore = &ps
}
prevConfig := &types.ChainConfig{}
paramstore.GetIfExists(ctx, types.ParamStoreKeyChainConfig, prevConfig)
defaultConfig := types.DefaultChainConfig()
prevConfig.GrayGlacierBlock = defaultConfig.GrayGlacierBlock
prevConfig.MergeNetsplitBlock = defaultConfig.MergeNetsplitBlock
paramstore.Set(ctx, types.ParamStoreKeyChainConfig, prevConfig)
return nil
}
+58
View File
@@ -0,0 +1,58 @@
package v3_test
import (
"fmt"
"testing"
v3 "github.com/cerc-io/laconicd/x/evm/migrations/v3"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/cerc-io/laconicd/encoding"
"github.com/cerc-io/laconicd/app"
v3types "github.com/cerc-io/laconicd/x/evm/migrations/v3/types"
"github.com/cerc-io/laconicd/x/evm/types"
)
func TestMigrateStore(t *testing.T) {
encCfg := encoding.MakeConfig(app.ModuleBasics)
evmKey := sdk.NewKVStoreKey(types.StoreKey)
tEvmKey := sdk.NewTransientStoreKey(fmt.Sprintf("%s_test", types.StoreKey))
ctx := testutil.DefaultContext(evmKey, tEvmKey)
paramstore := paramtypes.NewSubspace(
encCfg.Codec, encCfg.Amino, evmKey, tEvmKey, "evm",
).WithKeyTable(v3types.ParamKeyTable())
params := v3types.DefaultParams()
paramstore.SetParamSet(ctx, &params)
require.Panics(t, func() {
var preMigrationConfig types.ChainConfig
paramstore.Get(ctx, types.ParamStoreKeyChainConfig, &preMigrationConfig)
})
var preMigrationConfig v3types.ChainConfig
paramstore.Get(ctx, types.ParamStoreKeyChainConfig, &preMigrationConfig)
require.NotNil(t, preMigrationConfig.MergeForkBlock)
paramstore = paramtypes.NewSubspace(
encCfg.Codec, encCfg.Amino, evmKey, tEvmKey, "evm",
).WithKeyTable(types.ParamKeyTable())
err := v3.MigrateStore(ctx, &paramstore)
require.NoError(t, err)
updatedDefaultConfig := types.DefaultChainConfig()
var postMigrationConfig types.ChainConfig
paramstore.Get(ctx, types.ParamStoreKeyChainConfig, &postMigrationConfig)
require.Equal(t, postMigrationConfig.GrayGlacierBlock, updatedDefaultConfig.GrayGlacierBlock)
require.Equal(t, postMigrationConfig.MergeNetsplitBlock, updatedDefaultConfig.MergeNetsplitBlock)
require.Panics(t, func() {
var preMigrationConfig v3types.ChainConfig
paramstore.Get(ctx, types.ParamStoreKeyChainConfig, &preMigrationConfig)
})
}
+166
View File
@@ -0,0 +1,166 @@
package types
import (
"math/big"
"strings"
sdkmath "cosmossdk.io/math"
"github.com/cerc-io/laconicd/x/evm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params"
)
// EthereumConfig returns an Ethereum ChainConfig for EVM state transitions.
// All the negative or nil values are converted to nil
func (cc ChainConfig) EthereumConfig(chainID *big.Int) *params.ChainConfig {
return &params.ChainConfig{
ChainID: chainID,
HomesteadBlock: getBlockValue(cc.HomesteadBlock),
DAOForkBlock: getBlockValue(cc.DAOForkBlock),
DAOForkSupport: cc.DAOForkSupport,
EIP150Block: getBlockValue(cc.EIP150Block),
EIP150Hash: common.HexToHash(cc.EIP150Hash),
EIP155Block: getBlockValue(cc.EIP155Block),
EIP158Block: getBlockValue(cc.EIP158Block),
ByzantiumBlock: getBlockValue(cc.ByzantiumBlock),
ConstantinopleBlock: getBlockValue(cc.ConstantinopleBlock),
PetersburgBlock: getBlockValue(cc.PetersburgBlock),
IstanbulBlock: getBlockValue(cc.IstanbulBlock),
MuirGlacierBlock: getBlockValue(cc.MuirGlacierBlock),
BerlinBlock: getBlockValue(cc.BerlinBlock),
LondonBlock: getBlockValue(cc.LondonBlock),
ArrowGlacierBlock: getBlockValue(cc.ArrowGlacierBlock),
TerminalTotalDifficulty: nil,
Ethash: nil,
Clique: nil,
}
}
// DefaultChainConfig returns default evm parameters.
func DefaultChainConfig() ChainConfig {
homesteadBlock := sdk.ZeroInt()
daoForkBlock := sdk.ZeroInt()
eip150Block := sdk.ZeroInt()
eip155Block := sdk.ZeroInt()
eip158Block := sdk.ZeroInt()
byzantiumBlock := sdk.ZeroInt()
constantinopleBlock := sdk.ZeroInt()
petersburgBlock := sdk.ZeroInt()
istanbulBlock := sdk.ZeroInt()
muirGlacierBlock := sdk.ZeroInt()
berlinBlock := sdk.ZeroInt()
londonBlock := sdk.ZeroInt()
arrowGlacierBlock := sdk.ZeroInt()
mergeForkBlock := sdk.ZeroInt()
return ChainConfig{
HomesteadBlock: &homesteadBlock,
DAOForkBlock: &daoForkBlock,
DAOForkSupport: true,
EIP150Block: &eip150Block,
EIP150Hash: common.Hash{}.String(),
EIP155Block: &eip155Block,
EIP158Block: &eip158Block,
ByzantiumBlock: &byzantiumBlock,
ConstantinopleBlock: &constantinopleBlock,
PetersburgBlock: &petersburgBlock,
IstanbulBlock: &istanbulBlock,
MuirGlacierBlock: &muirGlacierBlock,
BerlinBlock: &berlinBlock,
LondonBlock: &londonBlock,
ArrowGlacierBlock: &arrowGlacierBlock,
MergeForkBlock: &mergeForkBlock,
}
}
func getBlockValue(block *sdkmath.Int) *big.Int {
if block == nil || block.IsNegative() {
return nil
}
return block.BigInt()
}
// Validate performs a basic validation of the ChainConfig params. The function will return an error
// if any of the block values is uninitialized (i.e nil) or if the EIP150Hash is an invalid hash.
func (cc ChainConfig) Validate() error {
if err := validateBlock(cc.HomesteadBlock); err != nil {
return sdkerrors.Wrap(err, "homesteadBlock")
}
if err := validateBlock(cc.DAOForkBlock); err != nil {
return sdkerrors.Wrap(err, "daoForkBlock")
}
if err := validateBlock(cc.EIP150Block); err != nil {
return sdkerrors.Wrap(err, "eip150Block")
}
if err := validateHash(cc.EIP150Hash); err != nil {
return err
}
if err := validateBlock(cc.EIP155Block); err != nil {
return sdkerrors.Wrap(err, "eip155Block")
}
if err := validateBlock(cc.EIP158Block); err != nil {
return sdkerrors.Wrap(err, "eip158Block")
}
if err := validateBlock(cc.ByzantiumBlock); err != nil {
return sdkerrors.Wrap(err, "byzantiumBlock")
}
if err := validateBlock(cc.ConstantinopleBlock); err != nil {
return sdkerrors.Wrap(err, "constantinopleBlock")
}
if err := validateBlock(cc.PetersburgBlock); err != nil {
return sdkerrors.Wrap(err, "petersburgBlock")
}
if err := validateBlock(cc.IstanbulBlock); err != nil {
return sdkerrors.Wrap(err, "istanbulBlock")
}
if err := validateBlock(cc.MuirGlacierBlock); err != nil {
return sdkerrors.Wrap(err, "muirGlacierBlock")
}
if err := validateBlock(cc.BerlinBlock); err != nil {
return sdkerrors.Wrap(err, "berlinBlock")
}
if err := validateBlock(cc.LondonBlock); err != nil {
return sdkerrors.Wrap(err, "londonBlock")
}
if err := validateBlock(cc.ArrowGlacierBlock); err != nil {
return sdkerrors.Wrap(err, "arrowGlacierBlock")
}
if err := validateBlock(cc.MergeForkBlock); err != nil {
return sdkerrors.Wrap(err, "mergeForkBlock")
}
// NOTE: chain ID is not needed to check config order
if err := cc.EthereumConfig(nil).CheckConfigForkOrder(); err != nil {
return sdkerrors.Wrap(err, "invalid config fork order")
}
return nil
}
func validateHash(hex string) error {
if hex != "" && strings.TrimSpace(hex) == "" {
return sdkerrors.Wrap(types.ErrInvalidChainConfig, "hash cannot be blank")
}
return nil
}
func validateBlock(block *sdkmath.Int) error {
// nil value means that the fork has not yet been applied
if block == nil {
return nil
}
if block.IsNegative() {
return sdkerrors.Wrapf(
types.ErrInvalidChainConfig, "block value cannot be negative: %s", block,
)
}
return nil
}
+3812
View File
File diff suppressed because it is too large Load Diff
+150
View File
@@ -0,0 +1,150 @@
package types
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/params"
"github.com/cerc-io/laconicd/types"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/ethereum/go-ethereum/core/vm"
)
var _ paramtypes.ParamSet = &Params{}
var (
// DefaultEVMDenom defines the default EVM denomination on Ethermint
DefaultEVMDenom = types.AttoPhoton
// DefaultMinGasMultiplier is 0.5 or 50%
DefaultMinGasMultiplier = sdk.NewDecWithPrec(50, 2)
// DefaultAllowUnprotectedTxs rejects all unprotected txs (i.e false)
DefaultAllowUnprotectedTxs = false
)
// Parameter keys
var (
ParamStoreKeyEVMDenom = []byte("EVMDenom")
ParamStoreKeyEnableCreate = []byte("EnableCreate")
ParamStoreKeyEnableCall = []byte("EnableCall")
ParamStoreKeyExtraEIPs = []byte("EnableExtraEIPs")
ParamStoreKeyChainConfig = []byte("ChainConfig")
ParamStoreKeyAllowUnprotectedTxs = []byte("AllowUnprotectedTxs")
// AvailableExtraEIPs define the list of all EIPs that can be enabled by the
// EVM interpreter. These EIPs are applied in order and can override the
// instruction sets from the latest hard fork enabled by the ChainConfig. For
// more info check:
// https://github.com/ethereum/go-ethereum/blob/master/core/vm/interpreter.go#L97
AvailableExtraEIPs = []int64{1344, 1884, 2200, 2929, 3198, 3529}
)
// ParamKeyTable returns the parameter key table.
func ParamKeyTable() paramtypes.KeyTable {
return paramtypes.NewKeyTable().RegisterParamSet(&Params{})
}
// NewParams creates a new Params instance
func NewParams(evmDenom string, enableCreate, enableCall bool, config ChainConfig, extraEIPs ...int64) Params {
return Params{
EvmDenom: evmDenom,
EnableCreate: enableCreate,
EnableCall: enableCall,
ExtraEIPs: extraEIPs,
ChainConfig: config,
}
}
// DefaultParams returns default evm parameters
// ExtraEIPs is empty to prevent overriding the latest hard fork instruction set
func DefaultParams() Params {
return Params{
EvmDenom: DefaultEVMDenom,
EnableCreate: true,
EnableCall: true,
ChainConfig: DefaultChainConfig(),
ExtraEIPs: nil,
AllowUnprotectedTxs: DefaultAllowUnprotectedTxs,
}
}
// ParamSetPairs returns the parameter set pairs.
func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
return paramtypes.ParamSetPairs{
paramtypes.NewParamSetPair(ParamStoreKeyEVMDenom, &p.EvmDenom, validateEVMDenom),
paramtypes.NewParamSetPair(ParamStoreKeyEnableCreate, &p.EnableCreate, validateBool),
paramtypes.NewParamSetPair(ParamStoreKeyEnableCall, &p.EnableCall, validateBool),
paramtypes.NewParamSetPair(ParamStoreKeyExtraEIPs, &p.ExtraEIPs, validateEIPs),
paramtypes.NewParamSetPair(ParamStoreKeyChainConfig, &p.ChainConfig, validateChainConfig),
paramtypes.NewParamSetPair(ParamStoreKeyAllowUnprotectedTxs, &p.AllowUnprotectedTxs, validateBool),
}
}
// Validate performs basic validation on evm parameters.
func (p Params) Validate() error {
if err := sdk.ValidateDenom(p.EvmDenom); err != nil {
return err
}
if err := validateEIPs(p.ExtraEIPs); err != nil {
return err
}
return p.ChainConfig.Validate()
}
// EIPs returns the ExtraEips as a int slice
func (p Params) EIPs() []int {
eips := make([]int, len(p.ExtraEIPs))
for i, eip := range p.ExtraEIPs {
eips[i] = int(eip)
}
return eips
}
func validateEVMDenom(i interface{}) error {
denom, ok := i.(string)
if !ok {
return fmt.Errorf("invalid parameter EVM denom type: %T", i)
}
return sdk.ValidateDenom(denom)
}
func validateBool(i interface{}) error {
_, ok := i.(bool)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
return nil
}
func validateEIPs(i interface{}) error {
eips, ok := i.([]int64)
if !ok {
return fmt.Errorf("invalid EIP slice type: %T", i)
}
for _, eip := range eips {
if !vm.ValidEip(int(eip)) {
return fmt.Errorf("EIP %d is not activateable, valid EIPS are: %s", eip, vm.ActivateableEips())
}
}
return nil
}
func validateChainConfig(i interface{}) error {
cfg, ok := i.(ChainConfig)
if !ok {
return fmt.Errorf("invalid chain config type: %T", i)
}
return cfg.Validate()
}
// IsLondon returns if london hardfork is enabled.
func IsLondon(ethConfig *params.ChainConfig, height int64) bool {
return ethConfig.IsLondon(big.NewInt(height))
}
+11 -3
View File
@@ -44,7 +44,7 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(_ *codec.LegacyAmino) {
// ConsensusVersion returns the consensus state-breaking version for the module.
func (AppModuleBasic) ConsensusVersion() uint64 {
return 1
return 3
}
// DefaultGenesis returns default genesis state as raw bytes for the evm
@@ -117,13 +117,21 @@ func (AppModule) Name() string {
func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
}
// RegisterQueryService registers a GRPC query service to respond to the
// RegisterServices registers a GRPC query service to respond to the
// module-specific GRPC queries.
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), am.keeper)
types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
_ = keeper.NewMigrator(*am.keeper)
m := keeper.NewMigrator(*am.keeper)
err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2)
if err != nil {
panic(err)
}
err = cfg.RegisterMigration(types.ModuleName, 2, m.Migrate2to3)
if err != nil {
panic(err)
}
}
// Route returns the message routing key for the evm module.
+6 -6
View File
@@ -10,18 +10,18 @@ import (
)
// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
// Value to the corresponding evm type.
// value to the corresponding EVM type.
func NewDecodeStore() func(kvA, kvB kv.Pair) string {
return func(kvA, kvB kv.Pair) string {
switch {
case bytes.Equal(kvA.Key[:1], types.KeyPrefixStorage):
storageHashA := common.BytesToHash(kvA.Value).Hex()
storageHashB := common.BytesToHash(kvB.Value).Hex()
storageA := common.BytesToHash(kvA.Value).Hex()
storageB := common.BytesToHash(kvB.Value).Hex()
return fmt.Sprintf("%v\n%v", storageHashA, storageHashB)
return fmt.Sprintf("%v\n%v", storageA, storageB)
case bytes.Equal(kvA.Key[:1], types.KeyPrefixCode):
codeHashA := common.BytesToHash(kvA.Value).Hex()
codeHashB := common.BytesToHash(kvB.Value).Hex()
codeHashA := common.Bytes2Hex(kvA.Value)
codeHashB := common.Bytes2Hex(kvB.Value)
return fmt.Sprintf("%v\n%v", codeHashA, codeHashB)
default:
+47
View File
@@ -0,0 +1,47 @@
package simulation
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/cerc-io/laconicd/x/evm/types"
"github.com/cosmos/cosmos-sdk/types/kv"
"github.com/ethereum/go-ethereum/common"
)
// TestDecodeStore tests that evm simulation decoder decodes the key value pairs as expected.
func TestDecodeStore(t *testing.T) {
dec := NewDecodeStore()
hash := common.BytesToHash([]byte("hash"))
code := common.Bytes2Hex([]byte{1, 2, 3})
kvPairs := kv.Pairs{
Pairs: []kv.Pair{
{Key: types.KeyPrefixCode, Value: common.FromHex(code)},
{Key: types.KeyPrefixStorage, Value: hash.Bytes()},
},
}
tests := []struct {
name string
expectedLog string
}{
{"Code", fmt.Sprintf("%v\n%v", code, code)},
{"Storage", fmt.Sprintf("%v\n%v", hash, hash)},
{"other", ""},
}
for i, tt := range tests {
i, tt := i, tt
t.Run(tt.name, func(t *testing.T) {
switch i {
case len(tests) - 1:
require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name)
default:
require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name)
}
})
}
}
+32 -8
View File
@@ -10,21 +10,45 @@ import (
"github.com/cerc-io/laconicd/x/evm/types"
)
// GenExtraEIPs randomly generates specific extra eips or not.
func genExtraEIPs(r *rand.Rand) []int64 {
const (
extraEIPsKey = "extra_eips"
)
// GenExtraEIPs defines a set of extra EIPs with 50% probability
func GenExtraEIPs(r *rand.Rand) []int64 {
var extraEIPs []int64
if r.Uint32()%2 == 0 {
// 50% chance of having extra EIPs
if r.Intn(2) == 0 {
extraEIPs = []int64{1344, 1884, 2200, 2929, 3198, 3529}
}
return extraEIPs
}
// RandomizedGenState generates a random GenesisState for nft
// GenEnableCreate enables the EnableCreate param with 80% probability
func GenEnableCreate(r *rand.Rand) bool {
// 80% chance of enabling create contract
enableCreate := r.Intn(100) < 80
return enableCreate
}
// GenEnableCall enables the EnableCall param with 80% probability
func GenEnableCall(r *rand.Rand) bool {
// 80% chance of enabling evm account transfer and calling contract
enableCall := r.Intn(100) < 80
return enableCall
}
// RandomizedGenState generates a random GenesisState for the EVM module
func RandomizedGenState(simState *module.SimulationState) {
params := types.NewParams(types.DefaultEVMDenom, true, true, types.DefaultChainConfig())
if simState.Rand.Uint32()%2 == 0 {
params = types.NewParams(types.DefaultEVMDenom, true, true, types.DefaultChainConfig(), 1344, 1884, 2200, 2929, 3198, 3529)
}
// evm params
var extraEIPs []int64
simState.AppParams.GetOrGenerate(
simState.Cdc, extraEIPsKey, &extraEIPs, simState.Rand,
func(r *rand.Rand) { extraEIPs = GenExtraEIPs(r) },
)
params := types.NewParams(types.DefaultEVMDenom, true, true, types.DefaultChainConfig(), extraEIPs...)
evmGenesis := types.NewGenesisState(params, []types.GenesisAccount{})
bz, err := json.MarshalIndent(evmGenesis, "", " ")
+51
View File
@@ -0,0 +1,51 @@
package simulation_test
import (
"encoding/json"
"math/rand"
"testing"
sdkmath "cosmossdk.io/math"
"github.com/stretchr/testify/require"
"github.com/cerc-io/laconicd/x/evm/simulation"
"github.com/cerc-io/laconicd/x/evm/types"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
)
// TestRandomizedGenState tests the normal scenario of applying RandomizedGenState.
// Abonormal scenarios are not tested here.
func TestRandomizedGenState(t *testing.T) {
registry := codectypes.NewInterfaceRegistry()
types.RegisterInterfaces(registry)
cdc := codec.NewProtoCodec(registry)
s := rand.NewSource(1)
r := rand.New(s)
simState := module.SimulationState{
AppParams: make(simtypes.AppParams),
Cdc: cdc,
Rand: r,
NumBonded: 3,
Accounts: simtypes.RandomAccounts(r, 3),
InitialStake: sdkmath.NewInt(1000),
GenState: make(map[string]json.RawMessage),
}
simulation.RandomizedGenState(&simState)
var evmGenesis types.GenesisState
simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &evmGenesis)
require.Equal(t, true, evmGenesis.Params.GetEnableCreate())
require.Equal(t, true, evmGenesis.Params.GetEnableCall())
require.Equal(t, types.DefaultEVMDenom, evmGenesis.Params.GetEvmDenom())
require.Equal(t, simulation.GenExtraEIPs(r), evmGenesis.Params.GetExtraEIPs())
require.Equal(t, types.DefaultChainConfig(), evmGenesis.Params.GetChainConfig())
require.Equal(t, len(evmGenesis.Accounts), 0)
}
+67 -57
View File
@@ -7,32 +7,29 @@ import (
"math/rand"
"time"
"cosmossdk.io/math"
sdkmath "cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cerc-io/laconicd/encoding"
"github.com/cerc-io/laconicd/server/config"
"github.com/cerc-io/laconicd/tests"
"github.com/cerc-io/laconicd/x/evm/keeper"
"github.com/cerc-io/laconicd/x/evm/types"
"github.com/cosmos/cosmos-sdk/client"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/ethereum/go-ethereum/crypto"
)
const (
@@ -118,7 +115,8 @@ func SimulateEthSimpleTransfer(ak types.AccountKeeper, k *keeper.Keeper) simtype
}
// SimulateEthCreateContract simulate create an ERC20 contract.
// It makes operationSimulateEthCallContract the future operations of SimulateEthCreateContract to ensure valid contract call.
// It makes operationSimulateEthCallContract the future operations of SimulateEthCreateContract
// to ensure valid contract call.
func SimulateEthCreateContract(ak types.AccountKeeper, k *keeper.Keeper) simtypes.Operation {
return func(
r *rand.Rand, bapp *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
@@ -128,7 +126,7 @@ func SimulateEthCreateContract(ak types.AccountKeeper, k *keeper.Keeper) simtype
from := common.BytesToAddress(simAccount.Address)
nonce := k.GetNonce(ctx, from)
ctorArgs, err := types.ERC20Contract.ABI.Pack("", from, math.NewIntWithDecimal(1000, 18).BigInt())
ctorArgs, err := types.ERC20Contract.ABI.Pack("", from, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "can not pack owner and supply"), nil, err
}
@@ -206,21 +204,28 @@ func SimulateEthTx(
}
// CreateRandomValidEthTx create the ethereum tx with valid random values
func CreateRandomValidEthTx(ctx *simulateContext, from, to *common.Address, amount *big.Int, data *hexutil.Bytes) (ethTx *types.MsgEthereumTx, err error) {
estimateGas, err := EstimateGas(ctx, from, to, data)
func CreateRandomValidEthTx(ctx *simulateContext,
from,
to *common.Address,
amount *big.Int,
data *hexutil.Bytes,
) (ethTx *types.MsgEthereumTx, err error) {
gasCap := ctx.rand.Uint64()
estimateGas, err := EstimateGas(ctx, from, to, data, gasCap)
if err != nil {
return nil, err
}
// we suppose that gasLimit should be larger than estimateGas to ensure tx validity
gasLimit := estimateGas + uint64(ctx.rand.Intn(int(sdktx.MaxGasWanted-estimateGas)))
ethChainID := ctx.keeper.ChainID()
chainConfig := ctx.keeper.GetParams(ctx.context).ChainConfig.EthereumConfig(ethChainID)
gasPrice := ctx.keeper.BaseFee(ctx.context, chainConfig)
gasPrice := ctx.keeper.GetBaseFee(ctx.context, chainConfig)
gasFeeCap := new(big.Int).Add(gasPrice, big.NewInt(int64(ctx.rand.Int())))
gasTipCap := big.NewInt(int64(ctx.rand.Int()))
nonce := ctx.keeper.GetNonce(ctx.context, *from)
if amount == nil {
amount, err = RandomTransferableAmount(ctx, *from, gasLimit, gasFeeCap)
amount, err = RandomTransferableAmount(ctx, *from, estimateGas, gasFeeCap)
if err != nil {
return nil, err
}
@@ -231,8 +236,51 @@ func CreateRandomValidEthTx(ctx *simulateContext, from, to *common.Address, amou
return ethTx, nil
}
// EstimateGas estimates the gas used by quering the keeper.
func EstimateGas(ctx *simulateContext, from, to *common.Address, data *hexutil.Bytes, gasCap uint64) (gas uint64, err error) {
args, err := json.Marshal(&types.TransactionArgs{To: to, From: from, Data: data})
if err != nil {
return 0, err
}
res, err := ctx.keeper.EstimateGas(sdk.WrapSDKContext(ctx.context), &types.EthCallRequest{
Args: args,
GasCap: gasCap,
})
if err != nil {
return 0, err
}
return res.Gas, nil
}
// RandomTransferableAmount generates a random valid transferable amount.
// Transferable amount is between the range [0, spendable), spendable = balance - gasFeeCap * GasLimit.
func RandomTransferableAmount(ctx *simulateContext, address common.Address, estimateGas uint64, gasFeeCap *big.Int) (amount *big.Int, err error) {
balance := ctx.keeper.GetBalance(ctx.context, address)
feeLimit := new(big.Int).Mul(gasFeeCap, big.NewInt(int64(estimateGas)))
if (feeLimit.Cmp(balance)) > 0 {
return nil, ErrNoEnoughBalance
}
spendable := new(big.Int).Sub(balance, feeLimit)
if spendable.Cmp(big.NewInt(0)) == 0 {
amount = new(big.Int).Set(spendable)
return amount, nil
}
simAmount, err := simtypes.RandPositiveInt(ctx.rand, sdkmath.NewIntFromBigInt(spendable))
if err != nil {
return nil, err
}
amount = simAmount.BigInt()
return amount, nil
}
// GetSignedTx sign the ethereum tx and packs it as a signing.Tx .
func GetSignedTx(ctx *simulateContext, txBuilder client.TxBuilder, msg *types.MsgEthereumTx, prv cryptotypes.PrivKey) (signedTx signing.Tx, err error) {
func GetSignedTx(
ctx *simulateContext,
txBuilder client.TxBuilder,
msg *types.MsgEthereumTx,
prv cryptotypes.PrivKey,
) (signedTx signing.Tx, err error) {
builder, ok := txBuilder.(tx.ExtensionOptionsTxBuilder)
if !ok {
return nil, fmt.Errorf("can not initiate ExtensionOptionsTxBuilder")
@@ -256,48 +304,10 @@ func GetSignedTx(ctx *simulateContext, txBuilder client.TxBuilder, msg *types.Ms
return nil, err
}
fees := sdk.NewCoins(sdk.NewCoin(ctx.keeper.GetParams(ctx.context).EvmDenom, sdk.NewIntFromBigInt(txData.Fee())))
fees := sdk.NewCoins(sdk.NewCoin(ctx.keeper.GetParams(ctx.context).EvmDenom, sdkmath.NewIntFromBigInt(txData.Fee())))
builder.SetFeeAmount(fees)
builder.SetGasLimit(msg.GetGas())
signedTx = builder.GetTx()
return signedTx, nil
}
// RandomTransferableAmount generates a random valid transferable amount.
// Transferable amount is between the range [0, spendable), spendable = balance - gasFeeCap * GasLimit.
func RandomTransferableAmount(ctx *simulateContext, address common.Address, gasLimit uint64, gasFeeCap *big.Int) (amount *big.Int, err error) {
balance := ctx.keeper.GetBalance(ctx.context, address)
feeLimit := new(big.Int).Mul(gasFeeCap, big.NewInt(int64(gasLimit)))
if (feeLimit.Cmp(balance)) > 0 {
return nil, ErrNoEnoughBalance
}
spendable := new(big.Int).Sub(balance, feeLimit)
if spendable.Cmp(big.NewInt(0)) == 0 {
amount = new(big.Int).Set(spendable)
return amount, nil
}
simAmount, err := simtypes.RandPositiveInt(ctx.rand, sdk.NewIntFromBigInt(spendable))
if err != nil {
return nil, err
}
amount = simAmount.BigInt()
return amount, nil
}
// EstimateGas estimates the gas used by quering the keeper.
func EstimateGas(ctx *simulateContext, from, to *common.Address, data *hexutil.Bytes) (gas uint64, err error) {
args, err := json.Marshal(&types.TransactionArgs{To: to, From: from, Data: data})
if err != nil {
return 0, err
}
res, err := ctx.keeper.EstimateGas(sdk.WrapSDKContext(ctx.context), &types.EthCallRequest{
Args: args,
GasCap: config.DefaultGasCap,
})
if err != nil {
return 0, err
}
return res.Gas, nil
}
+19 -6
View File
@@ -7,21 +7,34 @@ import (
"math/rand"
"github.com/cerc-io/laconicd/x/evm/types"
amino "github.com/cosmos/cosmos-sdk/codec"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/simulation"
)
const (
keyExtraEIPs = "ExtraEIPs"
)
// ParamChanges defines the parameters that can be modified by param change proposals
// on the simulation.
func ParamChanges(r *rand.Rand) []simtypes.ParamChange {
return []simtypes.ParamChange{
simulation.NewSimParamChange(types.ModuleName, keyExtraEIPs,
simulation.NewSimParamChange(types.ModuleName, string(types.ParamStoreKeyExtraEIPs),
func(r *rand.Rand) string {
return fmt.Sprintf("\"%d\"", genExtraEIPs(r))
extraEIPs := GenExtraEIPs(r)
amino := amino.NewLegacyAmino()
bz, err := amino.MarshalJSON(extraEIPs)
if err != nil {
panic(err)
}
return string(bz)
},
),
simulation.NewSimParamChange(types.ModuleName, string(types.ParamStoreKeyEnableCreate),
func(r *rand.Rand) string {
return fmt.Sprintf("%v", GenEnableCreate(r))
},
),
simulation.NewSimParamChange(types.ModuleName, string(types.ParamStoreKeyEnableCall),
func(r *rand.Rand) string {
return fmt.Sprintf("%v", GenEnableCall(r))
},
),
}
+44
View File
@@ -0,0 +1,44 @@
package simulation_test
import (
"encoding/json"
"fmt"
"math/rand"
"testing"
"github.com/stretchr/testify/require"
"github.com/cerc-io/laconicd/x/evm/simulation"
)
// TestParamChanges tests the paramChanges are generated as expected.
func TestParamChanges(t *testing.T) {
s := rand.NewSource(1)
r := rand.New(s)
extraEIPs := simulation.GenExtraEIPs(r)
bz, err := json.Marshal(extraEIPs)
require.NoError(t, err)
expected := []struct {
composedKey string
key string
simValue string
subspace string
}{
{"evm/EnableExtraEIPs", "EnableExtraEIPs", string(bz), "evm"},
{"evm/EnableCreate", "EnableCreate", fmt.Sprintf("%v", simulation.GenEnableCreate(r)), "evm"},
{"evm/EnableCall", "EnableCall", fmt.Sprintf("%v", simulation.GenEnableCall(r)), "evm"},
}
paramChanges := simulation.ParamChanges(r)
require.Len(t, paramChanges, 3)
for i, p := range paramChanges {
require.Equal(t, expected[i].composedKey, p.ComposedKey())
require.Equal(t, expected[i].key, p.Key())
require.Equal(t, expected[i].simValue, p.SimValue()(r))
require.Equal(t, expected[i].subspace, p.Subspace())
}
}
+70 -21
View File
@@ -6,32 +6,87 @@ order: 1
## EVM
The Ethereum Virtual Machine (EVM) is a computation engine which can be thought of as one single entity maintained by thousands of connected computers running an Ethereum client. It is considered to be the part of the Ethereum protocol that handles the deployment and execution of [smart contracts](https://ethereum.org/en/developers/docs/smart-contracts/).
The Ethereum Virtual Machine (EVM) is a computation engine which can be thought of as one single entity maintained by thousands of connected computers (nodes) running an Ethereum client. As a virtual machine ([VM](https://en.wikipedia.org/wiki/Virtual_machine)), the EVM is responisble for computing changes to the state deterministically regardless of its environment (hardware and OS). This means that every node has to get the exact same result given an identical starting state and transaction (tx).
To make a clear distinction: The Ethereum protocol describes a blockchain, in which all Ethereum accounts and smart contracts live. It has only one canonical state (a data structure, which keeps all accounts) at any given block in the chain. The EVM, however, is the [state machine](https://en.wikipedia.org/wiki/Finite-state_machine) that defines the rules for computing a new valid state from block to block. It is an isolated runtime, which means that code running inside the EVM has no access to network, filesystem, or other processes.
The EVM is considered to be the part of the Ethereum protocol that handles the deployment and execution of [smart contracts](https://ethereum.org/en/developers/docs/smart-contracts/). To make a clear distinction:
The `x/evm` module implements the EVM as a Cosmos SDK module. It allows users to interact with the EVM by submitting Ethereum transactions and executing their containing messages on the given state to evoke a state transition.
* The Ethereum protocol describes a blockchain, in which all Ethereum accounts and smart contracts live. It has only one canonical state (a data structure, which keeps all accounts) at any given block in the chain.
* The EVM, however, is the [state machine](https://en.wikipedia.org/wiki/Finite-state_machine) that defines the rules for computing a new valid state from block to block. It is an isolated runtime, which means that code running inside the EVM has no access to network, filesystem, or other processes (not external APIs).
### State Transition with Smart Contracts
The `x/evm` module implements the EVM as a Cosmos SDK module. It allows users to interact with the EVM by submitting Ethereum txs and executing their containing messages on the given state to evoke a state transition.
A state transition on the EVM can be initiated through a transaction that either deploys or calls a smart contract.
### State
Smart contracts are just like regular accounts on the blockchain, which additionally store executable code in an Ethereum-specific binary format (EVM bytecode). They are typically written in an Ethereum high level language, compiled into byte code using an EVM compiler, and finally deployed on the blockchain, by submitting a transaction using an Ethereum client. Whenever another account makes a message call to that deployed contract, it executes its EVM bytecode to perform calculations and further transactions.
The Ethereum state is a data structure, implemented as a [Merkle Patricia Trie](https://en.wikipedia.org/wiki/Merkle_tree), that keeps all accounts on the chain. The EVM makes changes to this data structure resulting in a new state with a different State Root. Ethereum can therefore be seen as a state chain that transitions from one state to another by executing transations in a block using the EVM. A new block of txs can be described through its Block header (parent hash, block number, time stamp, nonce, receipts,...).
### Opcodes
### Accounts
The EVM operates as a stack-based machine, where transactions carry a payload of Opcodes, that are used to specify the interaction with a smart contract.
There are two types of accounts that can be stored in state at a given address:
Typically contracts expose a public ABI, which is a list of supported ways a user can interact with a contract. To interact with a contract, a user will submit a transaction carrying any amount of wei (including 0) and a data payload formatted according to the ABI, specifying the type of interaction and any additional parameters. Each Opcode execution requires gas that needs to be payed with the transaction. The EVM is therefore considered quasi-turing complete, as it allows any arbitrary computation, but the amount of computations during a contract execution is limited to the amount gas provided in the transaction.
* **Externally Owned Account (EOA)**: Has nonce (tx counter) and balance
* **Smart Contract**: Has nonce, balance, (immutable) code hash, storage root (another Merkle Patricia Trie)
Smart contracts are just like regular accounts on the blockchain, which additionally store executable code in an Ethereum-specific binary format, known as **EVM bytecode**. They are typically written in an Ethereum high level language such as Solidity which is compiled down to EVM bytecode and deployed on the blockchain, by submitting a tx using an Ethereum client.
### Architecture
The EVM operates as a stack-based machine. It's main architecture components consist of:
* Virtual ROM: contract code is pulled into this read only memory when processing txs
* Machine state (volatile): changes as the EVM runs and is wiped clean after processing each tx
* Program counter (PC)
* Gas: keeps track of how much gas is used
* Stack and Memory: compute state changes
* Access to account storage (persistent)
### State Transitions with Smart Contracts
Typically smart contracts expose a public ABI, which is a list of supported ways a user can interact with a contract. To interact with a contract and invoke a state transition, a user will submit a tx carrying any amount of gas and a data payload formatted according to the ABI, specifying the type of interaction and any additional parameters. When the tx is received, the EVM executes the smart contracts's EVM bytecode using the tx payload.
### Executing EVM bytecode
A contract's EVM bytecode consists of basic operations (add, multiply, store, etc...), called **Opcodes**. Each Opcode execution requires gas that needs to be payed with the tx. The EVM is therefore considered quasi-turing complete, as it allows any arbitrary computation, but the amount of computations during a contract execution is limited to the amount of gas provided in the tx. Each Opcode's [**gas cost**](https://www.evm.codes/) reflects the cost of running these operations on actual computer hardware (e.g. `ADD = 3gas` and `SSTORE = 100gas`). To calculate the gas consumption of a tx, the gas cost is multiplied by the **gas price**, which can change depending on the demand of the network at the time. If the network is under heavy load, you might have to pay a highter gas price to get your tx executed. If the gas limit is hit (out of gas execption) no changes to the Ethereum state are applied, except that the sender's nonce increments and their balance goes down to pay for wasting the EVM's time.
Smart contracts can also call other smart contracts. Each call to a new contract creates a new instance of the EVM (including a new stack and memory). Each call passes the sandbox state to the next EVM. If the gas runs out, all state changes are discareded. Otherwise they are kept.
For further reading, please refer to:
- [EVM](https://eth.wiki/concepts/evm/evm)
- [EVM Architecture](https://cypherpunks-core.github.io/ethereumbook/13evm.html#evm_architecture)
- [What is Ethereum](https://ethdocs.org/en/latest/introduction/what-is-ethereum.html#what-is-ethereum)
- [Opcodes](https://www.ethervm.io/)
* [EVM](https://eth.wiki/concepts/evm/evm)
* [EVM Architecture](https://cypherpunks-core.github.io/ethereumbook/13evm.html#evm_architecture)
* [What is Ethereum](https://ethdocs.org/en/latest/introduction/what-is-ethereum.html#what-is-ethereum)
* [Opcodes](https://www.ethervm.io/)
## StateDB
## Ethermint as Geth implementation
Ethermint is an implementation of the [Etherum protocal in Golang](https://geth.ethereum.org/docs/getting-started) (Geth) as a Cosmos SDK module. Geth includes an implementation of the EVM to compute state transitions. Have a look at the [go-etheruem source code](https://github.com/ethereum/go-ethereum/blob/master/core/vm/instructions.go) to see how the EVM opcodes are implemented. Just as Geth can be run as an Ethereum node, Ethermint can be run as a node to compute state transitions with the EVM. Ethermint supports Geth's standard [Ethereum JSON-RPC APIs](https://docs.evmos.org/developers/json-rpc/endpoints.html) in order to be Web3 and EVM compatible.
### JSON-RPC
JSON-RPC is a stateless, lightweight remote procedure call (RPC) protocol. Primarily this specification defines several data structures and the rules around their processing. It is transport agnostic in that the concepts can be used within the same process, over sockets, over HTTP, or in many various message passing environments. It uses JSON (RFC 4627) as a data format.
#### JSON-RPC Example: `eth_call`
The JSON-RPC method [`eth_call`](https://docs.evmos.org/developers/json-rpc/endpoints.html#eth-call) allows you to execute messages against contracts. Usually, you need to send a transaction to a Geth node to include it in the mempool, then nodes gossip between each other and eventually the transaction is included in a block and gets executed. `eth_call` however lets you send data to a contract and see what happens without commiting a transaction.
In the Geth implementation, calling the endpoint roughly goes through the following steps:
1. The `eth_call` request is transformed to call the `func (s *PublicBlockchainAPI) Call()` function using the `eth` namespace
2. [`Call()`](https://github.com/ethereum/go-ethereum/blob/master/internal/ethapi/api.go#L982) is given the transaction arguments, the block to call against and optional overides that modify the state to call against. It then calls `DoCall()`
3. [`DoCall()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/internal/ethapi/api.go#L891) transforms the arguments into a `ethtypes.message`, instantiates an EVM and applies the message with `core.ApplyMessage`
4. [`ApplyMessage()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/core/state_transition.go#L180) calls the state transition `TransitionDb()`
5. [`TransitionDb()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/core/state_transition.go#L275) either `Create()`s a new contract or `Call()`s a contract
6. [`evm.Call()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/core/vm/evm.go#L168) runs the interpreter `evm.interpreter.Run()` to execute the message. If the execution fails, the state is reverted to a snapshot taken before the execution and gas is consumed.
7. [`Run()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/core/vm/interpreter.go#L116) performs a loop to execute the opcodes.
The ethermint implementatiom is similar and makes use of the gRPC query client which is included in the Cosmos SDK:
1. `eth_call` request is transformed to call the `func (e *PublicAPI) Call` function using the `eth` namespace
2. [`Call()`](https://github.com/evmos/ethermint/blob/main/rpc/namespaces/ethereum/eth/api.go#L639) calls `doCall()`
3. [`doCall()`](https://github.com/evmos/ethermint/blob/main/rpc/namespaces/ethereum/eth/api.go#L656) transforms the arguments into a `EthCallRequest` and calls `EthCall()` using the query client of the evm module.
4. [`EthCall()`](https://github.com/evmos/ethermint/blob/main/x/evm/keeper/grpc_query.go#L212) transforms the arguments into a `ethtypes.message` and calls `ApplyMessageWithConfig()
5. [`ApplyMessageWithConfig()`](https://github.com/evmos/ethermint/blob/d5598932a7f06158b7a5e3aa031bbc94eaaae32c/x/evm/keeper/state_transition.go#L341) instantiates an EVM and either `Create()`s a new contract or `Call()`s a contract using the Geth implementation.
### StateDB
The `StateDB` interface from [go-ethereum](https://github.com/ethereum/go-ethereum/blob/master/core/vm/interface.go) represents an EVM database for full state querying. EVM state transitions are enabled by this interface, which in the `x/evm` module is implemented by the `Keeper`. The implementation of this interface is what makes Ethermint EVM compatible.
@@ -41,12 +96,6 @@ The application using the `x/evm` module interacts with the Tendermint Core Cons
Ethereum transactions that are submitted to the `x/evm` module take part in a this consensus process before being executed and changing the application state. We encourage to understand the basics of the [Tendermint consensus engine](https://docs.tendermint.com/master/introduction/what-is-tendermint.html#intro-to-abci) in order to understand state transitions in detail.
## JSON-RPC
JSON-RPC is a stateless, lightweight remote procedure call (RPC) protocol. Primarily this specification defines several data structures and the rules around their processing. It is transport agnostic in that the concepts can be used within the same process, over sockets, over HTTP, or in many various message passing environments. It uses JSON (RFC 4627) as a data format.
Ethermint supports all standard web3 [JSON-RPC](https://evmos.dev/api/json-rpc/server.html) APIs. For more info check the client section.
## Transaction Logs
On every `x/evm` transaction, the result contains the Ethereum `Log`s from the state machine execution that are used by the JSON-RPC Web3 server for filter querying and for processing the EVM Hooks.
@@ -59,4 +108,4 @@ Bloom is the bloom filter value in bytes for each block that can be used for fil
::: tip
👉 **Note**: Since they are not stored on state, Transaction Logs and Block Blooms are not persisted after upgrades. A user must use an archival node after upgrades in order to obtain legacy chain events.
:::
:::
+71 -71
View File
@@ -28,55 +28,55 @@ The `StateDB` interface is implemented by the `StateDB` in the `x/evm/statedb` m
```go
// github.com/ethereum/go-ethereum/core/vm/interface.go
type StateDB interface {
CreateAccount(common.Address)
CreateAccount(common.Address)
SubBalance(common.Address, *big.Int)
AddBalance(common.Address, *big.Int)
GetBalance(common.Address) *big.Int
SubBalance(common.Address, *big.Int)
AddBalance(common.Address, *big.Int)
GetBalance(common.Address) *big.Int
GetNonce(common.Address) uint64
SetNonce(common.Address, uint64)
GetNonce(common.Address) uint64
SetNonce(common.Address, uint64)
GetCodeHash(common.Address) common.Hash
GetCode(common.Address) []byte
SetCode(common.Address, []byte)
GetCodeSize(common.Address) int
GetCodeHash(common.Address) common.Hash
GetCode(common.Address) []byte
SetCode(common.Address, []byte)
GetCodeSize(common.Address) int
AddRefund(uint64)
SubRefund(uint64)
GetRefund() uint64
AddRefund(uint64)
SubRefund(uint64)
GetRefund() uint64
GetCommittedState(common.Address, common.Hash) common.Hash
GetState(common.Address, common.Hash) common.Hash
SetState(common.Address, common.Hash, common.Hash)
GetCommittedState(common.Address, common.Hash) common.Hash
GetState(common.Address, common.Hash) common.Hash
SetState(common.Address, common.Hash, common.Hash)
Suicide(common.Address) bool
HasSuicided(common.Address) bool
Suicide(common.Address) bool
HasSuicided(common.Address) bool
// Exist reports whether the given account exists in state.
// Notably this should also return true for suicided accounts.
Exist(common.Address) bool
// Empty returns whether the given account is empty. Empty
// is defined according to EIP161 (balance = nonce = code = 0).
Empty(common.Address) bool
// Exist reports whether the given account exists in state.
// Notably this should also return true for suicided accounts.
Exist(common.Address) bool
// Empty returns whether the given account is empty. Empty
// is defined according to EIP161 (balance = nonce = code = 0).
Empty(common.Address) bool
PrepareAccessList(sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
AddressInAccessList(addr common.Address) bool
SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
// AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
// even if the feature/fork is not active yet
AddAddressToAccessList(addr common.Address)
// AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
// even if the feature/fork is not active yet
AddSlotToAccessList(addr common.Address, slot common.Hash)
PrepareAccessList(sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
AddressInAccessList(addr common.Address) bool
SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
// AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
// even if the feature/fork is not active yet
AddAddressToAccessList(addr common.Address)
// AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
// even if the feature/fork is not active yet
AddSlotToAccessList(addr common.Address, slot common.Hash)
RevertToSnapshot(int)
Snapshot() int
RevertToSnapshot(int)
Snapshot() int
AddLog(*types.Log)
AddPreimage(common.Hash, []byte)
AddLog(*types.Log)
AddPreimage(common.Hash, []byte)
ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error
ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error
}
```
@@ -137,10 +137,10 @@ marked as suicided.
Supports a transaction type that contains an [access list](https://eips.ethereum.org/EIPS/eip-2930), a list of addresses, and storage keys that the transaction plans to access. The access list state is kept in memory and discarded after the transaction committed.
- `PrepareAccessList()` handles the preparatory steps for executing a state transition with regards to both EIP-2929 and EIP-2930. This method should only be called if Yolov3/Berlin/2929+2930 is applicable at the current number.
- Add sender to access list (EIP-2929)
- Add destination to access list (EIP-2929)
- Add precompiles to access list (EIP-2929)
- Add the contents of the optional tx access list (EIP-2930)
- Add sender to access list (EIP-2929)
- Add destination to access list (EIP-2929)
- Add precompiles to access list (EIP-2929)
- Add the contents of the optional tx access list (EIP-2930)
- `AddressInAccessList()` returns true if the address is registered.
- `SlotInAccessList()` checks if the address and the slots are registered.
- `AddAddressToAccessList()` adds the given address to the access list. If the address is already in the access list, this function performs a no-op.
@@ -173,40 +173,40 @@ To support the interface functionality, it imports 4 module Keepers:
```go
type Keeper struct {
// Protobuf codec
cdc codec.BinaryCodec
// Store key required for the EVM Prefix KVStore. It is required by:
// - storing account's Storage State
// - storing account's Code
// - storing Bloom filters by block height. Needed for the Web3 API.
// For the full list, check the module specification
storeKey sdk.StoreKey
// Protobuf codec
cdc codec.BinaryCodec
// Store key required for the EVM Prefix KVStore. It is required by:
// - storing account's Storage State
// - storing account's Code
// - storing Bloom filters by block height. Needed for the Web3 API.
// For the full list, check the module specification
storeKey sdk.StoreKey
// key to access the transient store, which is reset on every block during Commit
transientKey sdk.StoreKey
// key to access the transient store, which is reset on every block during Commit
transientKey sdk.StoreKey
// module specific parameter space that can be configured through governance
paramSpace paramtypes.Subspace
// access to account state
accountKeeper types.AccountKeeper
// update balance and accounting operations with coins
bankKeeper types.BankKeeper
// access historical headers for EVM state transition execution
stakingKeeper types.StakingKeeper
// fetch EIP1559 base fee and parameters
feeMarketKeeper types.FeeMarketKeeper
// module specific parameter space that can be configured through governance
paramSpace paramtypes.Subspace
// access to account state
accountKeeper types.AccountKeeper
// update balance and accounting operations with coins
bankKeeper types.BankKeeper
// access historical headers for EVM state transition execution
stakingKeeper types.StakingKeeper
// fetch EIP1559 base fee and parameters
feeMarketKeeper types.FeeMarketKeeper
// chain ID number obtained from the context's chain id
eip155ChainID *big.Int
// chain ID number obtained from the context's chain id
eip155ChainID *big.Int
// Tracer used to collect execution traces from the EVM transaction execution
tracer string
// trace EVM state transition execution. This value is obtained from the `--trace` flag.
// For more info check https://geth.ethereum.org/docs/dapp/tracing
debug bool
// Tracer used to collect execution traces from the EVM transaction execution
tracer string
// trace EVM state transition execution. This value is obtained from the `--trace` flag.
// For more info check https://geth.ethereum.org/docs/dapp/tracing
debug bool
// EVM Hooks for tx post-processing
hooks types.EvmHooks
// EVM Hooks for tx post-processing
hooks types.EvmHooks
}
```
+9 -9
View File
@@ -41,17 +41,17 @@ The `anteHandler` is run for every transaction. It checks if the `Tx` is an Ethe
- `EthValidateBasicDecorator(evmKeeper)` validates the fields of a Ethereum type Cosmos `Tx` msg
- `EthSigVerificationDecorator(evmKeeper)` validates that the registered chain id is the same as the one on the message, and that the signer address matches the one defined on the message. It's not skipped for RecheckTx, because it set `From` address which is critical from other ante handler to work. Failure in RecheckTx will prevent tx to be included into block, especially when CheckTx succeed, in which case user won't see the error message.
- `EthAccountVerificationDecorator(ak, bankKeeper, evmKeeper)` that the sender balance is greater than the total transaction cost. The account will be set to store if it doesn't exist, i.e cannot be found on store. This AnteHandler decorator will fail if:
- any of the msgs is not a MsgEthereumTx
- from address is empty
- account balance is lower than the transaction cost
- any of the msgs is not a MsgEthereumTx
- from address is empty
- account balance is lower than the transaction cost
- `EthNonceVerificationDecorator(ak)` validates that the transaction nonces are valid and equivalent to the sender accounts current nonce.
- `EthGasConsumeDecorator(evmKeeper)` validates that the Ethereum tx message has enough to cover intrinsic gas (during CheckTx only) and that the sender has enough balance to pay for the gas cost. Intrinsic gas for a transaction is the amount of gas that the transaction uses before the transaction is executed. The gas is a constant value plus any cost incurred by additional bytes of data supplied with the transaction. This AnteHandler decorator will fail if:
- the transaction contains more than one message
- the message is not a MsgEthereumTx
- sender account cannot be found
- transaction's gas limit is lower than the intrinsic gas
- user doesn't have enough balance to deduct the transaction fees (gas_limit * gas_price)
- transaction or block gas meter runs out of gas
- the transaction contains more than one message
- the message is not a MsgEthereumTx
- sender account cannot be found
- transaction's gas limit is lower than the intrinsic gas
- user doesn't have enough balance to deduct the transaction fees (gas_limit * gas_price)
- transaction or block gas meter runs out of gas
- `CanTransferDecorator(evmKeeper, feeMarketKeeper)` creates an EVM from the message and calls the BlockContext CanTransfer function to see if the address can execute the transaction.
- `EthIncrementSenderSequenceDecorator(ak)` handles incrementing the sequence of the signer (i.e sender). If the transaction is a contract creation, the nonce will be incremented during the transaction execution and not within this AnteHandler decorator.
+112 -112
View File
@@ -12,16 +12,16 @@ An EVM state transition can be achieved by using the `MsgEthereumTx`. This messa
```go
type MsgEthereumTx struct {
// inner transaction data
Data *types.Any `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
// encoded storage size of the transaction
Size_ float64 `protobuf:"fixed64,2,opt,name=size,proto3" json:"-"`
// transaction hash in hex format
Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty" rlp:"-"`
// ethereum signer address in hex format. This address value is checked
// against the address derived from the signature (V, R, S) using the
// secp256k1 elliptic curve
From string `protobuf:"bytes,4,opt,name=from,proto3" json:"from,omitempty"`
// inner transaction data
Data *types.Any `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
// DEPRECATED: encoded storage size of the transaction
Size_ float64 `protobuf:"fixed64,2,opt,name=size,proto3" json:"-"`
// transaction hash in hex format
Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty" rlp:"-"`
// ethereum signer address in hex format. This address value is checked
// against the address derived from the signature (V, R, S) using the
// secp256k1 elliptic curve
From string `protobuf:"bytes,4,opt,name=from,proto3" json:"from,omitempty"`
}
```
@@ -46,35 +46,35 @@ The `MsgEthreumTx` can be converted to the go-ethereum `Transaction` and `Messag
```go
// AsTransaction creates an Ethereum Transaction type from the msg fields
func (msg MsgEthereumTx) AsTransaction() *ethtypes.Transaction {
txData, err := UnpackTxData(msg.Data)
if err != nil {
return nil
}
txData, err := UnpackTxData(msg.Data)
if err != nil {
return nil
}
return ethtypes.NewTx(txData.AsEthereumData())
return ethtypes.NewTx(txData.AsEthereumData())
}
// AsMessage returns the transaction as a core.Message.
func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
msg := Message{
nonce: tx.Nonce(),
gasLimit: tx.Gas(),
gasPrice: new(big.Int).Set(tx.GasPrice()),
gasFeeCap: new(big.Int).Set(tx.GasFeeCap()),
gasTipCap: new(big.Int).Set(tx.GasTipCap()),
to: tx.To(),
amount: tx.Value(),
data: tx.Data(),
accessList: tx.AccessList(),
isFake: false,
}
// If baseFee provided, set gasPrice to effectiveGasPrice.
if baseFee != nil {
msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.gasTipCap, baseFee), msg.gasFeeCap)
}
var err error
msg.from, err = Sender(s, tx)
return msg, err
msg := Message{
nonce: tx.Nonce(),
gasLimit: tx.Gas(),
gasPrice: new(big.Int).Set(tx.GasPrice()),
gasFeeCap: new(big.Int).Set(tx.GasFeeCap()),
gasTipCap: new(big.Int).Set(tx.GasTipCap()),
to: tx.To(),
amount: tx.Value(),
data: tx.Data(),
accessList: tx.AccessList(),
isFake: false,
}
// If baseFee provided, set gasPrice to effectiveGasPrice.
if baseFee != nil {
msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.gasTipCap, baseFee), msg.gasFeeCap)
}
var err error
msg.from, err = Sender(s, tx)
return msg, err
}
```
@@ -91,26 +91,26 @@ In order for the signature verification to be valid, the `TxData` must contain
// The function will fail if the sender address is not defined for the msg or if
// the sender is not registered on the keyring
func (msg *MsgEthereumTx) Sign(ethSigner ethtypes.Signer, keyringSigner keyring.Signer) error {
from := msg.GetFrom()
if from.Empty() {
return fmt.Errorf("sender address not defined for message")
}
from := msg.GetFrom()
if from.Empty() {
return fmt.Errorf("sender address not defined for message")
}
tx := msg.AsTransaction()
txHash := ethSigner.Hash(tx)
tx := msg.AsTransaction()
txHash := ethSigner.Hash(tx)
sig, _, err := keyringSigner.SignByAddress(from, txHash.Bytes())
if err != nil {
return err
}
sig, _, err := keyringSigner.SignByAddress(from, txHash.Bytes())
if err != nil {
return err
}
tx, err = tx.WithSignature(ethSigner, sig)
if err != nil {
return err
}
tx, err = tx.WithSignature(ethSigner, sig)
if err != nil {
return err
}
msg.FromEthereumTx(tx)
return nil
msg.FromEthereumTx(tx)
return nil
}
```
@@ -128,24 +128,24 @@ The transaction data of regular Ethereum transactions.
```go
type LegacyTx struct {
// nonce corresponds to the account nonce (transaction sequence).
Nonce uint64 `protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"`
// gas price defines the value for each gas unit
GasPrice *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=gas_price,json=gasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_price,omitempty"`
// gas defines the gas limit defined for the transaction.
GasLimit uint64 `protobuf:"varint,3,opt,name=gas,proto3" json:"gas,omitempty"`
// hex formatted address of the recipient
To string `protobuf:"bytes,4,opt,name=to,proto3" json:"to,omitempty"`
// value defines the unsigned integer value of the transaction amount.
Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,5,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"`
// input defines the data payload bytes of the transaction.
Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"`
// v defines the signature value
V []byte `protobuf:"bytes,7,opt,name=v,proto3" json:"v,omitempty"`
// r defines the signature value
R []byte `protobuf:"bytes,8,opt,name=r,proto3" json:"r,omitempty"`
// s define the signature value
S []byte `protobuf:"bytes,9,opt,name=s,proto3" json:"s,omitempty"`
// nonce corresponds to the account nonce (transaction sequence).
Nonce uint64 `protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"`
// gas price defines the value for each gas unit
GasPrice *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=gas_price,json=gasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_price,omitempty"`
// gas defines the gas limit defined for the transaction.
GasLimit uint64 `protobuf:"varint,3,opt,name=gas,proto3" json:"gas,omitempty"`
// hex formatted address of the recipient
To string `protobuf:"bytes,4,opt,name=to,proto3" json:"to,omitempty"`
// value defines the unsigned integer value of the transaction amount.
Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,5,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"`
// input defines the data payload bytes of the transaction.
Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"`
// v defines the signature value
V []byte `protobuf:"bytes,7,opt,name=v,proto3" json:"v,omitempty"`
// r defines the signature value
R []byte `protobuf:"bytes,8,opt,name=r,proto3" json:"r,omitempty"`
// s define the signature value
S []byte `protobuf:"bytes,9,opt,name=s,proto3" json:"s,omitempty"`
}
```
@@ -162,29 +162,29 @@ The transaction data of EIP-1559 dynamic fee transactions.
```go
type DynamicFeeTx struct {
// destination EVM chain ID
ChainID *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chainID"`
// nonce corresponds to the account nonce (transaction sequence).
Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"`
// gas tip cap defines the max value for the gas tip
GasTipCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=gas_tip_cap,json=gasTipCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_tip_cap,omitempty"`
// gas fee cap defines the max value for the gas fee
GasFeeCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=gas_fee_cap,json=gasFeeCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_fee_cap,omitempty"`
// gas defines the gas limit defined for the transaction.
GasLimit uint64 `protobuf:"varint,5,opt,name=gas,proto3" json:"gas,omitempty"`
// hex formatted address of the recipient
To string `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"`
// value defines the the transaction amount.
Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,7,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"`
// input defines the data payload bytes of the transaction.
Data []byte `protobuf:"bytes,8,opt,name=data,proto3" json:"data,omitempty"`
Accesses AccessList `protobuf:"bytes,9,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"`
// v defines the signature value
V []byte `protobuf:"bytes,10,opt,name=v,proto3" json:"v,omitempty"`
// r defines the signature value
R []byte `protobuf:"bytes,11,opt,name=r,proto3" json:"r,omitempty"`
// s define the signature value
S []byte `protobuf:"bytes,12,opt,name=s,proto3" json:"s,omitempty"`
// destination EVM chain ID
ChainID *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chainID"`
// nonce corresponds to the account nonce (transaction sequence).
Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"`
// gas tip cap defines the max value for the gas tip
GasTipCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=gas_tip_cap,json=gasTipCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_tip_cap,omitempty"`
// gas fee cap defines the max value for the gas fee
GasFeeCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=gas_fee_cap,json=gasFeeCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_fee_cap,omitempty"`
// gas defines the gas limit defined for the transaction.
GasLimit uint64 `protobuf:"varint,5,opt,name=gas,proto3" json:"gas,omitempty"`
// hex formatted address of the recipient
To string `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"`
// value defines the the transaction amount.
Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,7,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"`
// input defines the data payload bytes of the transaction.
Data []byte `protobuf:"bytes,8,opt,name=data,proto3" json:"data,omitempty"`
Accesses AccessList `protobuf:"bytes,9,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"`
// v defines the signature value
V []byte `protobuf:"bytes,10,opt,name=v,proto3" json:"v,omitempty"`
// r defines the signature value
R []byte `protobuf:"bytes,11,opt,name=r,proto3" json:"r,omitempty"`
// s define the signature value
S []byte `protobuf:"bytes,12,opt,name=s,proto3" json:"s,omitempty"`
}
```
@@ -204,27 +204,27 @@ The transaction data of EIP-2930 access list transactions.
```go
type AccessListTx struct {
// destination EVM chain ID
ChainID *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chainID"`
// nonce corresponds to the account nonce (transaction sequence).
Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"`
// gas price defines the value for each gas unit
GasPrice *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=gas_price,json=gasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_price,omitempty"`
// gas defines the gas limit defined for the transaction.
GasLimit uint64 `protobuf:"varint,4,opt,name=gas,proto3" json:"gas,omitempty"`
// hex formatted address of the recipient
To string `protobuf:"bytes,5,opt,name=to,proto3" json:"to,omitempty"`
// value defines the unsigned integer value of the transaction amount.
Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,6,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"`
// input defines the data payload bytes of the transaction.
Data []byte `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"`
Accesses AccessList `protobuf:"bytes,8,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"`
// v defines the signature value
V []byte `protobuf:"bytes,9,opt,name=v,proto3" json:"v,omitempty"`
// r defines the signature value
R []byte `protobuf:"bytes,10,opt,name=r,proto3" json:"r,omitempty"`
// s define the signature value
S []byte `protobuf:"bytes,11,opt,name=s,proto3" json:"s,omitempty"`
// destination EVM chain ID
ChainID *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chainID"`
// nonce corresponds to the account nonce (transaction sequence).
Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"`
// gas price defines the value for each gas unit
GasPrice *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=gas_price,json=gasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_price,omitempty"`
// gas defines the gas limit defined for the transaction.
GasLimit uint64 `protobuf:"varint,4,opt,name=gas,proto3" json:"gas,omitempty"`
// hex formatted address of the recipient
To string `protobuf:"bytes,5,opt,name=to,proto3" json:"to,omitempty"`
// value defines the unsigned integer value of the transaction amount.
Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,6,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"`
// input defines the data payload bytes of the transaction.
Data []byte `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"`
Accesses AccessList `protobuf:"bytes,8,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"`
// v defines the signature value
V []byte `protobuf:"bytes,9,opt,name=v,proto3" json:"v,omitempty"`
// r defines the signature value
R []byte `protobuf:"bytes,10,opt,name=r,proto3" json:"r,omitempty"`
// s define the signature value
S []byte `protobuf:"bytes,11,opt,name=s,proto3" json:"s,omitempty"`
}
```
+116 -103
View File
@@ -4,7 +4,9 @@ order: 6
# Hooks
The evm module implements an `EvmHooks` interface that extend the `Tx` processing logic externally. This supports EVM contracts to call native cosmos modules by
The `x/evm` module implements an `EvmHooks` interface that extend and customize the `Tx` processing logic externally.
This supports EVM contracts to call native cosmos modules by
1. defining a log signature and emitting the specific log from the smart contract,
2. recognizing those logs in the native tx processing code, and
@@ -14,7 +16,8 @@ To do this, the interface includes a `PostTxProcessing` hook that registers cus
```go
type EvmHooks interface {
PostTxProcessing(ctx sdk.Context, txHash common.Hash, logs []*ethtypes.Log) error
// Must be called after tx is processed successfully, if return an error, the whole transaction is reverted.
PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error
}
```
@@ -23,11 +26,11 @@ type EvmHooks interface {
`PostTxProcessing` is only called after a EVM transaction finished successfully and delegates the call to underlying hooks. If no hook has been registered, this function returns with a `nil` error.
```go
func (k *Keeper) PostTxProcessing(txHash common.Hash, logs []*ethtypes.Log) error {
if k.hooks == nil {
return nil
}
return k.hooks.PostTxProcessing(k.Ctx(), txHash, logs)
func (k *Keeper) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
if k.hooks == nil {
return nil
}
return k.hooks.PostTxProcessing(k.Ctx(), msg, receipt)
}
```
@@ -35,9 +38,9 @@ It's executed in the same cache context as the EVM transaction, if it returns an
The error returned by the hooks is translated to a VM error `failed to process native logs`, the detailed error message is stored in the return value. The message is sent to native modules asynchronously, there's no way for the caller to catch and recover the error.
## Use Case: Call Native erc20 Module on Evmos
## Use Case: Call Native ERC20 Module on Evmos
Here is an example taken from the [Evmos erc20 module](https://evmos.dev/modules/erc20/) that shows how the `EVMHooks` supports a contract calling a native module to convert ERC-20 Tokens intor Cosmos native Coins. Following the steps from above.
Here is an example taken from the Evmos [erc20 module](https://evmos.dev/modules/erc20/) that shows how the `EVMHooks` supports a contract calling a native module to convert ERC-20 Tokens into Cosmos native Coins. Following the steps from above.
You can define and emit a `Transfer` log signature in the smart contract like this:
@@ -45,14 +48,14 @@ You can define and emit a `Transfer` log signature in the smart contract like th
event Transfer(address indexed from, address indexed to, uint256 value);
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
```
@@ -63,115 +66,125 @@ The application will register a `BankSendHook` to the `EvmKeeper`. It recognizes
const ERC20EventTransfer = "Transfer"
// PostTxProcessing implements EvmHooks.PostTxProcessing
func (k Keeper) PostTxProcessing(ctx sdk.Context, txHash common.Hash, logs []*ethtypes.Log) error {
params := k.GetParams(ctx)
if !params.EnableEVMHook {
return sdkerrors.Wrap(types.ErrInternalTokenPair, "EVM Hook is currently disabled")
}
func (k Keeper) PostTxProcessing(
ctx sdk.Context,
msg core.Message,
receipt *ethtypes.Receipt,
) error {
params := h.k.GetParams(ctx)
if !params.EnableErc20 || !params.EnableEVMHook {
// no error is returned to allow for other post processing txs
// to pass
return nil
}
erc20 := contracts.ERC20BurnableContract.ABI
erc20 := contracts.ERC20BurnableContract.ABI
for i, log := range logs {
if len(log.Topics) < 3 {
continue
}
for i, log := range receipt.Logs {
if len(log.Topics) < 3 {
continue
}
eventID := log.Topics[0] // event ID
eventID := log.Topics[0] // event ID
event, err := erc20.EventByID(eventID)
if err != nil {
// invalid event for ERC20
continue
}
event, err := erc20.EventByID(eventID)
if err != nil {
// invalid event for ERC20
continue
}
if event.Name != types.ERC20EventTransfer {
k.Logger(ctx).Info("emitted event", "name", event.Name, "signature", event.Sig)
continue
}
if event.Name != types.ERC20EventTransfer {
h.k.Logger(ctx).Info("emitted event", "name", event.Name, "signature", event.Sig)
continue
}
transferEvent, err := erc20.Unpack(event.Name, log.Data)
if err != nil {
k.Logger(ctx).Error("failed to unpack transfer event", "error", err.Error())
continue
}
transferEvent, err := erc20.Unpack(event.Name, log.Data)
if err != nil {
h.k.Logger(ctx).Error("failed to unpack transfer event", "error", err.Error())
continue
}
if len(transferEvent) == 0 {
continue
}
if len(transferEvent) == 0 {
continue
}
tokens, ok := transferEvent[0].(*big.Int)
// safety check and ignore if amount not positive
if !ok || tokens == nil || tokens.Sign() != 1 {
continue
}
tokens, ok := transferEvent[0].(*big.Int)
// safety check and ignore if amount not positive
if !ok || tokens == nil || tokens.Sign() != 1 {
continue
}
// check that the contract is a registered token pair
contractAddr := log.Address
// check that the contract is a registered token pair
contractAddr := log.Address
id := k.GetERC20Map(ctx, contractAddr)
id := h.k.GetERC20Map(ctx, contractAddr)
if len(id) == 0 {
// no token is registered for the caller contract
continue
}
if len(id) == 0 {
// no token is registered for the caller contract
continue
}
pair, found := k.GetTokenPair(ctx, id)
if !found {
continue
}
pair, found := h.k.GetTokenPair(ctx, id)
if !found {
continue
}
// check that relaying for the pair is enabled
if !pair.Enabled {
return fmt.Errorf("internal relaying is disabled for pair %s, please create a governance proposal", contractAddr) // convert to SDK error
}
// check that conversion for the pair is enabled
if !pair.Enabled {
// continue to allow transfers for the ERC20 in case the token pair is disabled
h.k.Logger(ctx).Debug(
"ERC20 token -> Cosmos coin conversion is disabled for pair",
"coin", pair.Denom, "contract", pair.Erc20Address,
)
continue
}
// ignore as the burning always transfers to the zero address
to := common.BytesToAddress(log.Topics[2].Bytes())
if !bytes.Equal(to.Bytes(), types.ModuleAddress.Bytes()) {
continue
}
// ignore as the burning always transfers to the zero address
to := common.BytesToAddress(log.Topics[2].Bytes())
if !bytes.Equal(to.Bytes(), types.ModuleAddress.Bytes()) {
continue
}
// check that the event is Burn from the ERC20Burnable interface
// NOTE: assume that if they are burning the token that has been registered as a pair, they want to mint a Cosmos coin
// check that the event is Burn from the ERC20Burnable interface
// NOTE: assume that if they are burning the token that has been registered as a pair, they want to mint a Cosmos coin
// create the corresponding sdk.Coin that is paired with ERC20
coins := sdk.Coins{{Denom: pair.Denom, Amount: sdk.NewIntFromBigInt(tokens)}}
// create the corresponding sdk.Coin that is paired with ERC20
coins := sdk.Coins{{Denom: pair.Denom, Amount: sdk.NewIntFromBigInt(tokens)}}
// Mint the coin only if ERC20 is external
switch pair.ContractOwner {
case types.OWNER_MODULE:
_, err = k.CallEVM(ctx, erc20, types.ModuleAddress, contractAddr, "burn", tokens)
case types.OWNER_EXTERNAL:
err = k.bankKeeper.MintCoins(ctx, types.ModuleName, coins)
default:
err = types.ErrUndefinedOwner
}
// Mint the coin only if ERC20 is external
switch pair.ContractOwner {
case types.OWNER_MODULE:
_, err = h.k.CallEVM(ctx, erc20, types.ModuleAddress, contractAddr, true, "burn", tokens)
case types.OWNER_EXTERNAL:
err = h.k.bankKeeper.MintCoins(ctx, types.ModuleName, coins)
default:
err = types.ErrUndefinedOwner
}
if err != nil {
k.Logger(ctx).Debug(
"failed to process EVM hook for ER20 -> coin conversion",
"coin", pair.Denom, "contract", pair.Erc20Address, "error", err.Error(),
)
continue
}
if err != nil {
h.k.Logger(ctx).Debug(
"failed to process EVM hook for ER20 -> coin conversion",
"coin", pair.Denom, "contract", pair.Erc20Address, "error", err.Error(),
)
continue
}
// Only need last 20 bytes from log.topics
from := common.BytesToAddress(log.Topics[1].Bytes())
recipient := sdk.AccAddress(from.Bytes())
// Only need last 20 bytes from log.topics
from := common.BytesToAddress(log.Topics[1].Bytes())
recipient := sdk.AccAddress(from.Bytes())
// transfer the tokens from ModuleAccount to sender address
if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, coins); err != nil {
k.Logger(ctx).Debug(
"failed to process EVM hook for ER20 -> coin conversion",
"tx-hash", txHash.Hex(), "log-idx", i,
"coin", pair.Denom, "contract", pair.Erc20Address, "error", err.Error(),
)
continue
}
}
// transfer the tokens from ModuleAccount to sender address
if err := h.k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, coins); err != nil {
h.k.Logger(ctx).Debug(
"failed to process EVM hook for ER20 -> coin conversion",
"tx-hash", receipt.TxHash.Hex(), "log-idx", i,
"coin", pair.Denom, "contract", pair.Erc20Address, "error", err.Error(),
)
continue
}
}
return nil
}
return nil
```
Lastly, register the hook in `app.go`:
-1
View File
@@ -22,7 +22,6 @@ The `x/evm` module emits the Cosmos SDK events after a state execution. The EVM
| message | `"action"` | `"ethereum"` |
| message | `"module"` | `"evm"` |
Additionally, the EVM module emits an event during `EndBlock` for the filter query block bloom.
## ABCI
-1
View File
@@ -77,4 +77,3 @@ By default, all block configuration fields but `ConstantinopleBlock`, are enable
| MuirGlacierBlock | 0 |
| BerlinBlock | 0 |
| LondonBlock | 0 |
+1 -1
View File
@@ -104,4 +104,4 @@ For an overview on the JSON-RPC methods and namespaces supported on Ethermint,
| Verb | Method | Description |
| ------ | --------------------------------- | ------------------------------- |
| `gRPC` | `ethermint.evm.v1.Msg/EthereumTx` | Submit an Ethereum transactions |
| `POST` | `/ethermint/evm/v1/ethereum_tx` | Submit an Ethereum transactions |
| `POST` | `/ethermint/evm/v1/ethereum_tx` | Submit an Ethereum transactions |
+3 -3
View File
@@ -17,7 +17,7 @@ The growth of EVM-based chains (e.g. Ethereum), however, has uncovered several s
The `x/evm` module provides this EVM familiarity on a scalable, high-throughput Proof-of-Stake blockchain. It is built as a [Cosmos SDK module](https://docs.cosmos.network/master/building-modules/intro.html) which allows for the deployment of smart contracts, interaction with the EVM state machine (state transitions), and the use of EVM tooling. It can be used on Cosmos application-specific blockchains, which alleviate the aforementioned concerns through high transaction throughput via [Tendermint Core](https://github.com/tendermint/tendermint), fast transaction finality, and horizontal scalability via [IBC](https://ibcprotocol.org/).
The `x/evm` is part of the [ethermint library](https://pkg.go.dev/github.com/cerc-io/laconicd). For an example of how Ethermint can be used on any Cosmos-SDK chain, please refer to [Evmos](https://www.github.com/tharsis/evmos).
The `x/evm` is part of the [ethermint library](https://pkg.go.dev/github.com/evmos/ethermint). For an example of how Ethermint can be used on any Cosmos-SDK chain, please refer to [Evmos](https://www.github.com/tharsis/evmos).
## Contents
@@ -34,8 +34,8 @@ The `x/evm` is part of the [ethermint library](https://pkg.go.dev/github.com/cer
## Module Architecture
> **NOTE:**: If you're not familiar with the overall module structure from
> the SDK modules, please check this [document](https://docs.cosmos.network/master/building-modules/structure.html) as
> prerequisite reading.
the SDK modules, please check this [document](https://docs.cosmos.network/master/building-modules/structure.html) as
prerequisite reading.
```shell
evm/
+11
View File
@@ -3,8 +3,19 @@ package statedb
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
)
// ExtStateDB defines an extension to the interface provided by the go-ethereum
// codebase to support additional state transition functionalities. In particular
// it supports appending a new entry to the state journal through
// AppendJournalEntry so that the state can be reverted after running
// stateful precompiled contracts.
type ExtStateDB interface {
vm.StateDB
AppendJournalEntry(JournalEntry)
}
// Keeper provide underlying storage of StateDB
type Keeper interface {
// Read methods
+36 -36
View File
@@ -24,21 +24,21 @@ import (
"github.com/ethereum/go-ethereum/common"
)
// journalEntry is a modification entry in the state change journal that can be
// reverted on demand.
type journalEntry interface {
// revert undoes the changes introduced by this journal entry.
revert(*StateDB)
// JournalEntry is a modification entry in the state change journal that can be
// Reverted on demand.
type JournalEntry interface {
// Revert undoes the changes introduced by this journal entry.
Revert(*StateDB)
// dirtied returns the Ethereum address modified by this journal entry.
dirtied() *common.Address
// Dirtied returns the Ethereum address modified by this journal entry.
Dirtied() *common.Address
}
// journal contains the list of state modifications applied since the last state
// commit. These are tracked to be able to be reverted in the case of an execution
// exception or request for reversal.
type journal struct {
entries []journalEntry // Current changes tracked by the journal
entries []JournalEntry // Current changes tracked by the journal
dirties map[common.Address]int // Dirty accounts and the number of changes
}
@@ -64,22 +64,22 @@ func (j *journal) sortedDirties() []common.Address {
}
// append inserts a new modification entry to the end of the change journal.
func (j *journal) append(entry journalEntry) {
func (j *journal) append(entry JournalEntry) {
j.entries = append(j.entries, entry)
if addr := entry.dirtied(); addr != nil {
if addr := entry.Dirtied(); addr != nil {
j.dirties[*addr]++
}
}
// revert undoes a batch of journalled modifications along with any reverted
// Revert undoes a batch of journalled modifications along with any Reverted
// dirty handling too.
func (j *journal) revert(statedb *StateDB, snapshot int) {
func (j *journal) Revert(statedb *StateDB, snapshot int) {
for i := len(j.entries) - 1; i >= snapshot; i-- {
// Undo the changes made by the operation
j.entries[i].revert(statedb)
j.entries[i].Revert(statedb)
// Drop any dirty tracking induced by the change
if addr := j.entries[i].dirtied(); addr != nil {
if addr := j.entries[i].Dirtied(); addr != nil {
if j.dirties[*addr]--; j.dirties[*addr] == 0 {
delete(j.dirties, *addr)
}
@@ -141,23 +141,23 @@ type (
}
)
func (ch createObjectChange) revert(s *StateDB) {
func (ch createObjectChange) Revert(s *StateDB) {
delete(s.stateObjects, *ch.account)
}
func (ch createObjectChange) dirtied() *common.Address {
func (ch createObjectChange) Dirtied() *common.Address {
return ch.account
}
func (ch resetObjectChange) revert(s *StateDB) {
func (ch resetObjectChange) Revert(s *StateDB) {
s.setStateObject(ch.prev)
}
func (ch resetObjectChange) dirtied() *common.Address {
func (ch resetObjectChange) Dirtied() *common.Address {
return nil
}
func (ch suicideChange) revert(s *StateDB) {
func (ch suicideChange) Revert(s *StateDB) {
obj := s.getStateObject(*ch.account)
if obj != nil {
obj.suicided = ch.prev
@@ -165,59 +165,59 @@ func (ch suicideChange) revert(s *StateDB) {
}
}
func (ch suicideChange) dirtied() *common.Address {
func (ch suicideChange) Dirtied() *common.Address {
return ch.account
}
func (ch balanceChange) revert(s *StateDB) {
func (ch balanceChange) Revert(s *StateDB) {
s.getStateObject(*ch.account).setBalance(ch.prev)
}
func (ch balanceChange) dirtied() *common.Address {
func (ch balanceChange) Dirtied() *common.Address {
return ch.account
}
func (ch nonceChange) revert(s *StateDB) {
func (ch nonceChange) Revert(s *StateDB) {
s.getStateObject(*ch.account).setNonce(ch.prev)
}
func (ch nonceChange) dirtied() *common.Address {
func (ch nonceChange) Dirtied() *common.Address {
return ch.account
}
func (ch codeChange) revert(s *StateDB) {
func (ch codeChange) Revert(s *StateDB) {
s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
}
func (ch codeChange) dirtied() *common.Address {
func (ch codeChange) Dirtied() *common.Address {
return ch.account
}
func (ch storageChange) revert(s *StateDB) {
func (ch storageChange) Revert(s *StateDB) {
s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
}
func (ch storageChange) dirtied() *common.Address {
func (ch storageChange) Dirtied() *common.Address {
return ch.account
}
func (ch refundChange) revert(s *StateDB) {
func (ch refundChange) Revert(s *StateDB) {
s.refund = ch.prev
}
func (ch refundChange) dirtied() *common.Address {
func (ch refundChange) Dirtied() *common.Address {
return nil
}
func (ch addLogChange) revert(s *StateDB) {
func (ch addLogChange) Revert(s *StateDB) {
s.logs = s.logs[:len(s.logs)-1]
}
func (ch addLogChange) dirtied() *common.Address {
func (ch addLogChange) Dirtied() *common.Address {
return nil
}
func (ch accessListAddAccountChange) revert(s *StateDB) {
func (ch accessListAddAccountChange) Revert(s *StateDB) {
/*
One important invariant here, is that whenever a (addr, slot) is added, if the
addr is not already present, the add causes two journal entries:
@@ -230,14 +230,14 @@ func (ch accessListAddAccountChange) revert(s *StateDB) {
s.accessList.DeleteAddress(*ch.address)
}
func (ch accessListAddAccountChange) dirtied() *common.Address {
func (ch accessListAddAccountChange) Dirtied() *common.Address {
return nil
}
func (ch accessListAddSlotChange) revert(s *StateDB) {
func (ch accessListAddSlotChange) Revert(s *StateDB) {
s.accessList.DeleteSlot(*ch.address, *ch.slot)
}
func (ch accessListAddSlotChange) dirtied() *common.Address {
func (ch accessListAddSlotChange) Dirtied() *common.Address {
return nil
}
+3 -3
View File
@@ -250,8 +250,8 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject)
// CreateAccount is called during the EVM CREATE operation. The situation might arise that
// a contract does the following:
//
// 1. sends funds to sha(account ++ (nonce + 1))
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
// 1. sends funds to sha(account ++ (nonce + 1))
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
//
// Carrying over the balance ensures that Ether doesn't disappear.
func (s *StateDB) CreateAccount(addr common.Address) {
@@ -429,7 +429,7 @@ func (s *StateDB) RevertToSnapshot(revid int) {
snapshot := s.validRevisions[idx].journalIndex
// Replay the journal to undo changes and remove invalidated snapshots
s.journal.revert(s, snapshot)
s.journal.Revert(s, snapshot)
s.validRevisions = s.validRevisions[:idx]
}
+15 -8
View File
@@ -3,11 +3,13 @@ package types
import (
"math/big"
"github.com/cerc-io/laconicd/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkmath "cosmossdk.io/math"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/cerc-io/laconicd/types"
)
func newAccessListTx(tx *ethtypes.Transaction) (*AccessListTx, error) {
@@ -23,7 +25,7 @@ func newAccessListTx(tx *ethtypes.Transaction) (*AccessListTx, error) {
}
if tx.Value() != nil {
amountInt, err := SafeNewIntFromBigInt(tx.Value())
amountInt, err := types.SafeNewIntFromBigInt(tx.Value())
if err != nil {
return nil, err
}
@@ -31,7 +33,7 @@ func newAccessListTx(tx *ethtypes.Transaction) (*AccessListTx, error) {
}
if tx.GasPrice() != nil {
gasPriceInt, err := SafeNewIntFromBigInt(tx.GasPrice())
gasPriceInt, err := types.SafeNewIntFromBigInt(tx.GasPrice())
if err != nil {
return nil, err
}
@@ -172,7 +174,7 @@ func (tx *AccessListTx) SetSignatureValues(chainID, v, r, s *big.Int) {
tx.S = s.Bytes()
}
if chainID != nil {
chainIDInt := sdk.NewIntFromBigInt(chainID)
chainIDInt := sdkmath.NewIntFromBigInt(chainID)
tx.ChainID = &chainIDInt
}
}
@@ -183,7 +185,7 @@ func (tx AccessListTx) Validate() error {
if gasPrice == nil {
return sdkerrors.Wrap(ErrInvalidGasPrice, "cannot be nil")
}
if !IsValidInt256(gasPrice) {
if !types.IsValidInt256(gasPrice) {
return sdkerrors.Wrap(ErrInvalidGasPrice, "out of bound")
}
@@ -196,11 +198,11 @@ func (tx AccessListTx) Validate() error {
if amount != nil && amount.Sign() == -1 {
return sdkerrors.Wrapf(ErrInvalidAmount, "amount cannot be negative %s", amount)
}
if !IsValidInt256(amount) {
if !types.IsValidInt256(amount) {
return sdkerrors.Wrap(ErrInvalidAmount, "out of bound")
}
if !IsValidInt256(tx.Fee()) {
if !types.IsValidInt256(tx.Fee()) {
return sdkerrors.Wrap(ErrInvalidGasFee, "out of bound")
}
@@ -230,6 +232,11 @@ func (tx AccessListTx) Cost() *big.Int {
return cost(tx.Fee(), tx.GetValue())
}
// EffectiveGasPrice is the same as GasPrice for AccessListTx
func (tx AccessListTx) EffectiveGasPrice(baseFee *big.Int) *big.Int {
return tx.GetGasPrice()
}
// EffectiveFee is the same as Fee for AccessListTx
func (tx AccessListTx) EffectiveFee(baseFee *big.Int) *big.Int {
return tx.Fee()
+167
View File
@@ -0,0 +1,167 @@
package types
import (
"math/big"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
func (suite *TxDataTestSuite) TestAccessListTxCopy() {
tx := &AccessListTx{}
txCopy := tx.Copy()
suite.Require().Equal(&AccessListTx{}, txCopy)
}
func (suite *TxDataTestSuite) TestAccessListTxGetGasTipCap() {
testCases := []struct {
name string
tx AccessListTx
exp *big.Int
}{
{
"non-empty gasPrice",
AccessListTx{
GasPrice: &suite.sdkInt,
},
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.GetGasTipCap()
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestAccessListTxGetGasFeeCap() {
testCases := []struct {
name string
tx AccessListTx
exp *big.Int
}{
{
"non-empty gasPrice",
AccessListTx{
GasPrice: &suite.sdkInt,
},
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.GetGasFeeCap()
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestEmptyAccessList() {
testCases := []struct {
name string
tx AccessListTx
}{
{
"empty access list tx",
AccessListTx{
Accesses: nil,
},
},
}
for _, tc := range testCases {
actual := tc.tx.GetAccessList()
suite.Require().Nil(actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestAccessListTxCost() {
testCases := []struct {
name string
tx AccessListTx
exp *big.Int
}{
{
"non-empty access list tx",
AccessListTx{
GasPrice: &suite.sdkInt,
GasLimit: uint64(1),
Amount: &suite.sdkZeroInt,
},
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.Cost()
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestAccessListEffectiveGasPrice() {
testCases := []struct {
name string
tx AccessListTx
baseFee *big.Int
}{
{
"non-empty access list tx",
AccessListTx{
GasPrice: &suite.sdkInt,
},
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.EffectiveGasPrice(tc.baseFee)
suite.Require().Equal(tc.tx.GetGasPrice(), actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestAccessListTxEffectiveCost() {
testCases := []struct {
name string
tx AccessListTx
baseFee *big.Int
exp *big.Int
}{
{
"non-empty access list tx",
AccessListTx{
GasPrice: &suite.sdkInt,
GasLimit: uint64(1),
Amount: &suite.sdkZeroInt,
},
(&suite.sdkInt).BigInt(),
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.EffectiveCost(tc.baseFee)
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestAccessListTxType() {
testCases := []struct {
name string
tx AccessListTx
}{
{
"non-empty access list tx",
AccessListTx{},
},
}
for _, tc := range testCases {
actual := tc.tx.TxType()
suite.Require().Equal(uint8(ethtypes.AccessListTxType), actual, tc.name)
}
}
+15 -7
View File
@@ -4,6 +4,8 @@ import (
"math/big"
"strings"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -31,7 +33,8 @@ func (cc ChainConfig) EthereumConfig(chainID *big.Int) *params.ChainConfig {
BerlinBlock: getBlockValue(cc.BerlinBlock),
LondonBlock: getBlockValue(cc.LondonBlock),
ArrowGlacierBlock: getBlockValue(cc.ArrowGlacierBlock),
MergeForkBlock: getBlockValue(cc.MergeForkBlock),
GrayGlacierBlock: getBlockValue(cc.GrayGlacierBlock),
MergeNetsplitBlock: getBlockValue(cc.MergeNetsplitBlock),
TerminalTotalDifficulty: nil,
Ethash: nil,
Clique: nil,
@@ -53,7 +56,8 @@ func DefaultChainConfig() ChainConfig {
berlinBlock := sdk.ZeroInt()
londonBlock := sdk.ZeroInt()
arrowGlacierBlock := sdk.ZeroInt()
mergeForkBlock := sdk.ZeroInt()
grayGlacierBlock := sdk.ZeroInt()
mergeNetsplitBlock := sdk.ZeroInt()
return ChainConfig{
HomesteadBlock: &homesteadBlock,
@@ -71,11 +75,12 @@ func DefaultChainConfig() ChainConfig {
BerlinBlock: &berlinBlock,
LondonBlock: &londonBlock,
ArrowGlacierBlock: &arrowGlacierBlock,
MergeForkBlock: &mergeForkBlock,
GrayGlacierBlock: &grayGlacierBlock,
MergeNetsplitBlock: &mergeNetsplitBlock,
}
}
func getBlockValue(block *sdk.Int) *big.Int {
func getBlockValue(block *sdkmath.Int) *big.Int {
if block == nil || block.IsNegative() {
return nil
}
@@ -128,8 +133,11 @@ func (cc ChainConfig) Validate() error {
if err := validateBlock(cc.ArrowGlacierBlock); err != nil {
return sdkerrors.Wrap(err, "arrowGlacierBlock")
}
if err := validateBlock(cc.MergeForkBlock); err != nil {
return sdkerrors.Wrap(err, "mergeForkBlock")
if err := validateBlock(cc.GrayGlacierBlock); err != nil {
return sdkerrors.Wrap(err, "GrayGlacierBlock")
}
if err := validateBlock(cc.MergeNetsplitBlock); err != nil {
return sdkerrors.Wrap(err, "MergeNetsplitBlock")
}
// NOTE: chain ID is not needed to check config order
@@ -147,7 +155,7 @@ func validateHash(hex string) error {
return nil
}
func validateBlock(block *sdk.Int) error {
func validateBlock(block *sdkmath.Int) error {
// nil value means that the fork has not yet been applied
if block == nil {
return nil
+66 -4
View File
@@ -3,17 +3,16 @@ package types
import (
"testing"
sdkmath "cosmossdk.io/math"
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
)
var defaultEIP150Hash = common.Hash{}.String()
func newIntPtr(i int64) *sdk.Int {
v := sdk.NewInt(i)
func newIntPtr(i int64) *sdkmath.Int {
v := sdkmath.NewInt(i)
return &v
}
@@ -236,6 +235,69 @@ func TestChainConfigValidate(t *testing.T) {
},
true,
},
{
"invalid ArrowGlacierBlock",
ChainConfig{
HomesteadBlock: newIntPtr(0),
DAOForkBlock: newIntPtr(0),
EIP150Block: newIntPtr(0),
EIP150Hash: defaultEIP150Hash,
EIP155Block: newIntPtr(0),
EIP158Block: newIntPtr(0),
ByzantiumBlock: newIntPtr(0),
ConstantinopleBlock: newIntPtr(0),
PetersburgBlock: newIntPtr(0),
IstanbulBlock: newIntPtr(0),
MuirGlacierBlock: newIntPtr(0),
BerlinBlock: newIntPtr(0),
LondonBlock: newIntPtr(0),
ArrowGlacierBlock: newIntPtr(-1),
},
true,
},
{
"invalid GrayGlacierBlock",
ChainConfig{
HomesteadBlock: newIntPtr(0),
DAOForkBlock: newIntPtr(0),
EIP150Block: newIntPtr(0),
EIP150Hash: defaultEIP150Hash,
EIP155Block: newIntPtr(0),
EIP158Block: newIntPtr(0),
ByzantiumBlock: newIntPtr(0),
ConstantinopleBlock: newIntPtr(0),
PetersburgBlock: newIntPtr(0),
IstanbulBlock: newIntPtr(0),
MuirGlacierBlock: newIntPtr(0),
BerlinBlock: newIntPtr(0),
LondonBlock: newIntPtr(0),
ArrowGlacierBlock: newIntPtr(0),
GrayGlacierBlock: newIntPtr(-1),
},
true,
},
{
"invalid MergeNetsplitBlock",
ChainConfig{
HomesteadBlock: newIntPtr(0),
DAOForkBlock: newIntPtr(0),
EIP150Block: newIntPtr(0),
EIP150Hash: defaultEIP150Hash,
EIP155Block: newIntPtr(0),
EIP158Block: newIntPtr(0),
ByzantiumBlock: newIntPtr(0),
ConstantinopleBlock: newIntPtr(0),
PetersburgBlock: newIntPtr(0),
IstanbulBlock: newIntPtr(0),
MuirGlacierBlock: newIntPtr(0),
BerlinBlock: newIntPtr(0),
LondonBlock: newIntPtr(0),
ArrowGlacierBlock: newIntPtr(0),
GrayGlacierBlock: newIntPtr(0),
MergeNetsplitBlock: newIntPtr(-1),
},
true,
},
{
"invalid fork order - skip HomesteadBlock",
ChainConfig{
+3 -15
View File
@@ -1,6 +1,7 @@
package types
import (
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -9,10 +10,7 @@ import (
proto "github.com/gogo/protobuf/proto"
)
type (
TxResponse interface{}
ExtensionOptionsEthereumTxI interface{}
)
var ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry())
// RegisterInterfaces registers the client interfaces to protobuf Any.
func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
@@ -31,23 +29,13 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
&AccessListTx{},
&LegacyTx{},
)
registry.RegisterInterface(
"ethermint.evm.v1.MsgEthereumTxResponse",
(*TxResponse)(nil),
&MsgEthereumTxResponse{},
)
registry.RegisterInterface(
"ethermint.evm.v1.ExtensionOptionsEthereumTx",
(*ExtensionOptionsEthereumTxI)(nil),
&ExtensionOptionsEthereumTx{},
)
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
}
// PackClientState constructs a new Any packed with the given tx data value. It returns
// an error if the client state can't be casted to a protobuf message or if the concrete
// implemention is not registered to the protobuf codec.
// implementation is not registered to the protobuf codec.
func PackTxData(txData TxData) (*codectypes.Any, error) {
msg, ok := txData.(proto.Message)
if !ok {
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"github.com/ethereum/go-ethereum/params"
)
// EVMConfig encapulates common parameters needed to create an EVM to execute a message
// EVMConfig encapsulates common parameters needed to create an EVM to execute a message
// It's mainly to reduce the number of method parameters
type EVMConfig struct {
Params Params
+13 -14
View File
@@ -3,11 +3,10 @@ package types
import (
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkmath "cosmossdk.io/math"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/cerc-io/laconicd/types"
@@ -26,7 +25,7 @@ func newDynamicFeeTx(tx *ethtypes.Transaction) (*DynamicFeeTx, error) {
}
if tx.Value() != nil {
amountInt, err := SafeNewIntFromBigInt(tx.Value())
amountInt, err := types.SafeNewIntFromBigInt(tx.Value())
if err != nil {
return nil, err
}
@@ -34,7 +33,7 @@ func newDynamicFeeTx(tx *ethtypes.Transaction) (*DynamicFeeTx, error) {
}
if tx.GasFeeCap() != nil {
gasFeeCapInt, err := SafeNewIntFromBigInt(tx.GasFeeCap())
gasFeeCapInt, err := types.SafeNewIntFromBigInt(tx.GasFeeCap())
if err != nil {
return nil, err
}
@@ -42,7 +41,7 @@ func newDynamicFeeTx(tx *ethtypes.Transaction) (*DynamicFeeTx, error) {
}
if tx.GasTipCap() != nil {
gasTipCapInt, err := SafeNewIntFromBigInt(tx.GasTipCap())
gasTipCapInt, err := types.SafeNewIntFromBigInt(tx.GasTipCap())
if err != nil {
return nil, err
}
@@ -188,7 +187,7 @@ func (tx *DynamicFeeTx) SetSignatureValues(chainID, v, r, s *big.Int) {
tx.S = s.Bytes()
}
if chainID != nil {
chainIDInt := sdk.NewIntFromBigInt(chainID)
chainIDInt := sdkmath.NewIntFromBigInt(chainID)
tx.ChainID = &chainIDInt
}
}
@@ -211,11 +210,11 @@ func (tx DynamicFeeTx) Validate() error {
return sdkerrors.Wrapf(ErrInvalidGasCap, "gas fee cap cannot be negative %s", tx.GasFeeCap)
}
if !IsValidInt256(tx.GetGasTipCap()) {
if !types.IsValidInt256(tx.GetGasTipCap()) {
return sdkerrors.Wrap(ErrInvalidGasCap, "out of bound")
}
if !IsValidInt256(tx.GetGasFeeCap()) {
if !types.IsValidInt256(tx.GetGasFeeCap()) {
return sdkerrors.Wrap(ErrInvalidGasCap, "out of bound")
}
@@ -226,7 +225,7 @@ func (tx DynamicFeeTx) Validate() error {
)
}
if !IsValidInt256(tx.Fee()) {
if !types.IsValidInt256(tx.Fee()) {
return sdkerrors.Wrap(ErrInvalidGasFee, "out of bound")
}
@@ -235,7 +234,7 @@ func (tx DynamicFeeTx) Validate() error {
if amount != nil && amount.Sign() == -1 {
return sdkerrors.Wrapf(ErrInvalidAmount, "amount cannot be negative %s", amount)
}
if !IsValidInt256(amount) {
if !types.IsValidInt256(amount) {
return sdkerrors.Wrap(ErrInvalidAmount, "out of bound")
}
@@ -265,14 +264,14 @@ func (tx DynamicFeeTx) Cost() *big.Int {
return cost(tx.Fee(), tx.GetValue())
}
// GetEffectiveGasPrice returns the effective gas price
func (tx *DynamicFeeTx) GetEffectiveGasPrice(baseFee *big.Int) *big.Int {
return math.BigMin(new(big.Int).Add(tx.GasTipCap.BigInt(), baseFee), tx.GasFeeCap.BigInt())
// EffectiveGasPrice returns the effective gas price
func (tx *DynamicFeeTx) EffectiveGasPrice(baseFee *big.Int) *big.Int {
return EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt())
}
// EffectiveFee returns effective_gasprice * gaslimit.
func (tx DynamicFeeTx) EffectiveFee(baseFee *big.Int) *big.Int {
return fee(tx.GetEffectiveGasPrice(baseFee), tx.GasLimit)
return fee(tx.EffectiveGasPrice(baseFee), tx.GasLimit)
}
// EffectiveCost returns amount + effective_gasprice * gaslimit.
+184 -11
View File
@@ -4,9 +4,12 @@ import (
"math/big"
"testing"
sdkmath "cosmossdk.io/math"
"github.com/cerc-io/laconicd/tests"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/suite"
)
@@ -14,25 +17,35 @@ import (
type TxDataTestSuite struct {
suite.Suite
sdkInt sdk.Int
sdkInt sdkmath.Int
uint64 uint64
hexUint64 hexutil.Uint64
bigInt *big.Int
sdkZeroInt sdk.Int
sdkMinusOneInt sdk.Int
hexBigInt hexutil.Big
overflowBigInt *big.Int
sdkZeroInt sdkmath.Int
sdkMinusOneInt sdkmath.Int
invalidAddr string
addr common.Address
hexAddr string
hexDataBytes hexutil.Bytes
hexInputBytes hexutil.Bytes
}
func (suite *TxDataTestSuite) SetupTest() {
suite.sdkInt = sdk.NewInt(100)
suite.sdkInt = sdkmath.NewInt(100)
suite.uint64 = suite.sdkInt.Uint64()
suite.hexUint64 = hexutil.Uint64(100)
suite.bigInt = big.NewInt(1)
suite.hexBigInt = hexutil.Big(*big.NewInt(1))
suite.overflowBigInt = big.NewInt(0).Exp(big.NewInt(10), big.NewInt(256), nil)
suite.sdkZeroInt = sdk.ZeroInt()
suite.sdkMinusOneInt = sdk.NewInt(-1)
suite.sdkMinusOneInt = sdkmath.NewInt(-1)
suite.invalidAddr = "123456"
suite.addr = tests.GenerateAddress()
suite.hexAddr = suite.addr.Hex()
suite.hexDataBytes = hexutil.Bytes([]byte("data"))
suite.hexInputBytes = hexutil.Bytes([]byte("input"))
}
func TestTxDataTestSuite(t *testing.T) {
@@ -41,12 +54,14 @@ func TestTxDataTestSuite(t *testing.T) {
func (suite *TxDataTestSuite) TestNewDynamicFeeTx() {
testCases := []struct {
name string
tx *ethtypes.Transaction
name string
expError bool
tx *ethtypes.Transaction
}{
{
"non-empty tx",
ethtypes.NewTx(&ethtypes.AccessListTx{ // TODO: change to DynamicFeeTx on Geth
false,
ethtypes.NewTx(&ethtypes.DynamicFeeTx{
Nonce: 1,
Data: []byte("data"),
Gas: 100,
@@ -58,16 +73,96 @@ func (suite *TxDataTestSuite) TestNewDynamicFeeTx() {
S: suite.bigInt,
}),
},
{
"value out of bounds tx",
true,
ethtypes.NewTx(&ethtypes.DynamicFeeTx{
Nonce: 1,
Data: []byte("data"),
Gas: 100,
Value: suite.overflowBigInt,
AccessList: ethtypes.AccessList{},
To: &suite.addr,
V: suite.bigInt,
R: suite.bigInt,
S: suite.bigInt,
}),
},
{
"gas fee cap out of bounds tx",
true,
ethtypes.NewTx(&ethtypes.DynamicFeeTx{
Nonce: 1,
Data: []byte("data"),
Gas: 100,
GasFeeCap: suite.overflowBigInt,
Value: big.NewInt(1),
AccessList: ethtypes.AccessList{},
To: &suite.addr,
V: suite.bigInt,
R: suite.bigInt,
S: suite.bigInt,
}),
},
{
"gas tip cap out of bounds tx",
true,
ethtypes.NewTx(&ethtypes.DynamicFeeTx{
Nonce: 1,
Data: []byte("data"),
Gas: 100,
GasTipCap: suite.overflowBigInt,
Value: big.NewInt(1),
AccessList: ethtypes.AccessList{},
To: &suite.addr,
V: suite.bigInt,
R: suite.bigInt,
S: suite.bigInt,
}),
},
}
for _, tc := range testCases {
tx, err := newDynamicFeeTx(tc.tx)
suite.Require().NoError(err)
suite.Require().NotEmpty(tx)
suite.Require().Equal(uint8(2), tx.TxType())
if tc.expError {
suite.Require().Error(err)
} else {
suite.Require().NoError(err)
suite.Require().NotEmpty(tx)
suite.Require().Equal(uint8(2), tx.TxType())
}
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxAsEthereumData() {
feeConfig := &ethtypes.DynamicFeeTx{
Nonce: 1,
Data: []byte("data"),
Gas: 100,
Value: big.NewInt(1),
AccessList: ethtypes.AccessList{},
To: &suite.addr,
V: suite.bigInt,
R: suite.bigInt,
S: suite.bigInt,
}
tx := ethtypes.NewTx(feeConfig)
dynamicFeeTx, err := newDynamicFeeTx(tx)
suite.Require().NoError(err)
res := dynamicFeeTx.AsEthereumData()
resTx := ethtypes.NewTx(res)
suite.Require().Equal(feeConfig.Nonce, resTx.Nonce())
suite.Require().Equal(feeConfig.Data, resTx.Data())
suite.Require().Equal(feeConfig.Gas, resTx.Gas())
suite.Require().Equal(feeConfig.Value, resTx.Value())
suite.Require().Equal(feeConfig.AccessList, resTx.AccessList())
suite.Require().Equal(feeConfig.To, resTx.To())
}
func (suite *TxDataTestSuite) TestDynamicFeeTxCopy() {
tx := &DynamicFeeTx{}
txCopy := tx.Copy()
@@ -495,6 +590,84 @@ func (suite *TxDataTestSuite) TestDynamicFeeTxValidate() {
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxEffectiveGasPrice() {
testCases := []struct {
name string
tx DynamicFeeTx
baseFee *big.Int
exp *big.Int
}{
{
"non-empty dynamic fee tx",
DynamicFeeTx{
GasTipCap: &suite.sdkInt,
GasFeeCap: &suite.sdkInt,
},
(&suite.sdkInt).BigInt(),
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.EffectiveGasPrice(tc.baseFee)
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxEffectiveFee() {
testCases := []struct {
name string
tx DynamicFeeTx
baseFee *big.Int
exp *big.Int
}{
{
"non-empty dynamic fee tx",
DynamicFeeTx{
GasTipCap: &suite.sdkInt,
GasFeeCap: &suite.sdkInt,
GasLimit: uint64(1),
},
(&suite.sdkInt).BigInt(),
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.EffectiveFee(tc.baseFee)
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxEffectiveCost() {
testCases := []struct {
name string
tx DynamicFeeTx
baseFee *big.Int
exp *big.Int
}{
{
"non-empty dynamic fee tx",
DynamicFeeTx{
GasTipCap: &suite.sdkInt,
GasFeeCap: &suite.sdkInt,
GasLimit: uint64(1),
Amount: &suite.sdkZeroInt,
},
(&suite.sdkInt).BigInt(),
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.EffectiveCost(tc.baseFee)
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxFeeCost() {
tx := &DynamicFeeTx{}
suite.Require().Panics(func() { tx.Fee() }, "should panic")
+4
View File
@@ -33,6 +33,7 @@ const (
codeErrInvalidBaseFee
codeErrGasOverflow
codeErrInvalidAccount
codeErrInvalidGasLimit
)
var ErrPostTxProcessing = errors.New("failed to execute post processing")
@@ -97,6 +98,9 @@ var (
// ErrInvalidAccount returns an error if the account is not an EVM compatible account
ErrInvalidAccount = sdkerrors.Register(ModuleName, codeErrInvalidAccount, "account type is not a valid ethereum account")
// ErrInvalidGasLimit returns an error if gas limit value is invalid
ErrInvalidGasLimit = sdkerrors.Register(ModuleName, codeErrInvalidGasLimit, "invalid gas limit")
)
// NewExecErrorWithReason unpacks the revert return bytes and returns a wrapped error
+209 -106
View File
@@ -37,6 +37,9 @@ type Params struct {
ExtraEIPs []int64 `protobuf:"varint,4,rep,packed,name=extra_eips,json=extraEips,proto3" json:"extra_eips,omitempty" yaml:"extra_eips"`
// chain config defines the EVM chain configuration parameters
ChainConfig ChainConfig `protobuf:"bytes,5,opt,name=chain_config,json=chainConfig,proto3" json:"chain_config" yaml:"chain_config"`
// Allow unprotected transactions defines if replay-protected (i.e non EIP155
// signed) transactions can be executed on the state machine.
AllowUnprotectedTxs bool `protobuf:"varint,6,opt,name=allow_unprotected_txs,json=allowUnprotectedTxs,proto3" json:"allow_unprotected_txs,omitempty"`
}
func (m *Params) Reset() { *m = Params{} }
@@ -107,6 +110,13 @@ func (m *Params) GetChainConfig() ChainConfig {
return ChainConfig{}
}
func (m *Params) GetAllowUnprotectedTxs() bool {
if m != nil {
return m.AllowUnprotectedTxs
}
return false
}
// ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int values
// instead of *big.Int.
type ChainConfig struct {
@@ -141,8 +151,10 @@ type ChainConfig struct {
LondonBlock *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,17,opt,name=london_block,json=londonBlock,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"london_block,omitempty" yaml:"london_block"`
// Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated)
ArrowGlacierBlock *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,18,opt,name=arrow_glacier_block,json=arrowGlacierBlock,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"arrow_glacier_block,omitempty" yaml:"arrow_glacier_block"`
// EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in merge proceedings)
MergeForkBlock *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,19,opt,name=merge_fork_block,json=mergeForkBlock,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"merge_fork_block,omitempty" yaml:"merge_fork_block"`
// EIP-5133 (bomb delay) switch block (nil = no fork, 0 = already activated)
GrayGlacierBlock *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,20,opt,name=gray_glacier_block,json=grayGlacierBlock,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gray_glacier_block,omitempty" yaml:"gray_glacier_block"`
// Virtual fork after The Merge to use as a network splitter
MergeNetsplitBlock *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,21,opt,name=merge_netsplit_block,json=mergeNetsplitBlock,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"merge_netsplit_block,omitempty" yaml:"merge_netsplit_block"`
}
func (m *ChainConfig) Reset() { *m = ChainConfig{} }
@@ -657,100 +669,104 @@ func init() {
func init() { proto.RegisterFile("ethermint/evm/v1/evm.proto", fileDescriptor_d21ecc92c8c8583e) }
var fileDescriptor_d21ecc92c8c8583e = []byte{
// 1476 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xcf, 0x4e, 0x1c, 0x37,
0x18, 0x07, 0x76, 0x81, 0x59, 0xef, 0xb0, 0x3b, 0x18, 0x42, 0x37, 0x44, 0x65, 0xe8, 0x1c, 0x5a,
0x2a, 0x25, 0x6c, 0x20, 0x42, 0x8d, 0x12, 0xf5, 0xc0, 0x02, 0x49, 0xa0, 0x69, 0x8b, 0x0c, 0x55,
0xa5, 0x4a, 0xd5, 0xc8, 0x3b, 0xe3, 0x0c, 0x53, 0x66, 0xc6, 0x2b, 0xdb, 0xb3, 0xd9, 0xad, 0xfa,
0x00, 0x95, 0x7a, 0xe9, 0x23, 0xf4, 0x15, 0xfa, 0x16, 0x51, 0x4f, 0xb9, 0x54, 0xaa, 0x7a, 0x18,
0x45, 0xe4, 0xc6, 0x71, 0x9f, 0xa0, 0x1a, 0xdb, 0xfb, 0x17, 0xd4, 0x16, 0x4e, 0xeb, 0xdf, 0xf7,
0xe7, 0xf7, 0xb3, 0x3f, 0x7f, 0x1e, 0x7b, 0xc1, 0x2a, 0x11, 0x67, 0x84, 0xc5, 0x61, 0x22, 0xea,
0xa4, 0x1d, 0xd7, 0xdb, 0x5b, 0xf9, 0xcf, 0x66, 0x8b, 0x51, 0x41, 0xa1, 0x35, 0xf0, 0x6d, 0xe6,
0xc6, 0xf6, 0xd6, 0xea, 0x72, 0x40, 0x03, 0x2a, 0x9d, 0xf5, 0x7c, 0xa4, 0xe2, 0x9c, 0x3f, 0x67,
0xc0, 0xdc, 0x31, 0x66, 0x38, 0xe6, 0x70, 0x0b, 0x94, 0x48, 0x3b, 0x76, 0x7d, 0x92, 0xd0, 0xb8,
0x36, 0xbd, 0x3e, 0xbd, 0x51, 0x6a, 0x2c, 0xf7, 0x32, 0xdb, 0xea, 0xe2, 0x38, 0x7a, 0xe2, 0x0c,
0x5c, 0x0e, 0x32, 0x48, 0x3b, 0xde, 0xcf, 0x87, 0xf0, 0x73, 0xb0, 0x40, 0x12, 0xdc, 0x8c, 0x88,
0xeb, 0x31, 0x82, 0x05, 0xa9, 0xcd, 0xac, 0x4f, 0x6f, 0x18, 0x8d, 0x5a, 0x2f, 0xb3, 0x97, 0x75,
0xda, 0xa8, 0xdb, 0x41, 0xa6, 0xc2, 0x7b, 0x12, 0xc2, 0xcf, 0x40, 0xb9, 0xef, 0xc7, 0x51, 0x54,
0x2b, 0xc8, 0xe4, 0x95, 0x5e, 0x66, 0xc3, 0xf1, 0x64, 0x1c, 0x45, 0x0e, 0x02, 0x3a, 0x15, 0x47,
0x11, 0xdc, 0x05, 0x80, 0x74, 0x04, 0xc3, 0x2e, 0x09, 0x5b, 0xbc, 0x56, 0x5c, 0x2f, 0x6c, 0x14,
0x1a, 0xce, 0x45, 0x66, 0x97, 0x0e, 0x72, 0xeb, 0xc1, 0xe1, 0x31, 0xef, 0x65, 0xf6, 0xa2, 0x26,
0x19, 0x04, 0x3a, 0xa8, 0x24, 0xc1, 0x41, 0xd8, 0xe2, 0xf0, 0x7b, 0x60, 0x7a, 0x67, 0x38, 0x4c,
0x5c, 0x8f, 0x26, 0xaf, 0xc2, 0xa0, 0x36, 0xbb, 0x3e, 0xbd, 0x51, 0xde, 0xfe, 0x70, 0x73, 0xb2,
0x6e, 0x9b, 0x7b, 0x79, 0xd4, 0x9e, 0x0c, 0x6a, 0xdc, 0x7b, 0x93, 0xd9, 0x53, 0xbd, 0xcc, 0x5e,
0x52, 0xd4, 0xa3, 0x04, 0x0e, 0x2a, 0x7b, 0xc3, 0x48, 0xe7, 0xf7, 0x0a, 0x28, 0x8f, 0x64, 0xc2,
0x18, 0x54, 0xcf, 0x68, 0x4c, 0xb8, 0x20, 0xd8, 0x77, 0x9b, 0x11, 0xf5, 0xce, 0x75, 0x89, 0xf7,
0xff, 0xce, 0xec, 0x8f, 0x83, 0x50, 0x9c, 0xa5, 0xcd, 0x4d, 0x8f, 0xc6, 0x75, 0x8f, 0xf2, 0x98,
0x72, 0xfd, 0xf3, 0x80, 0xfb, 0xe7, 0x75, 0xd1, 0x6d, 0x11, 0xbe, 0x79, 0x98, 0x88, 0x5e, 0x66,
0xaf, 0x28, 0xe1, 0x09, 0x2a, 0x07, 0x55, 0x06, 0x96, 0x46, 0x6e, 0x80, 0x5d, 0x50, 0xf1, 0x31,
0x75, 0x5f, 0x51, 0x76, 0xae, 0xd5, 0x66, 0xa4, 0xda, 0xc9, 0xff, 0x57, 0xbb, 0xc8, 0x6c, 0x73,
0x7f, 0xf7, 0xeb, 0x67, 0x94, 0x9d, 0x4b, 0xce, 0x5e, 0x66, 0xdf, 0x51, 0xea, 0xe3, 0xcc, 0x0e,
0x32, 0x7d, 0x4c, 0x07, 0x61, 0xf0, 0x5b, 0x60, 0x0d, 0x02, 0x78, 0xda, 0x6a, 0x51, 0x26, 0xf4,
0xce, 0x3e, 0xb8, 0xc8, 0xec, 0x8a, 0xa6, 0x3c, 0x51, 0x9e, 0x5e, 0x66, 0x7f, 0x30, 0x41, 0xaa,
0x73, 0x1c, 0x54, 0xd1, 0xb4, 0x3a, 0x14, 0x72, 0x60, 0x92, 0xb0, 0xb5, 0xb5, 0xf3, 0x50, 0xaf,
0xa8, 0x28, 0x57, 0x74, 0x7c, 0xa3, 0x15, 0x95, 0x0f, 0x0e, 0x8f, 0xb7, 0x76, 0x1e, 0xf6, 0x17,
0xa4, 0xf7, 0x71, 0x94, 0xd6, 0x41, 0x65, 0x05, 0xd5, 0x6a, 0x0e, 0x81, 0x86, 0xee, 0x19, 0xe6,
0x67, 0xb2, 0x4b, 0x4a, 0x8d, 0x8d, 0x8b, 0xcc, 0x06, 0x8a, 0xe9, 0x05, 0xe6, 0x67, 0xc3, 0x7d,
0x69, 0x76, 0x7f, 0xc4, 0x89, 0x08, 0xd3, 0xb8, 0xcf, 0x05, 0x54, 0x72, 0x1e, 0x35, 0x98, 0xff,
0x8e, 0x9e, 0xff, 0xdc, 0xad, 0xe7, 0xbf, 0x73, 0xdd, 0xfc, 0x77, 0xc6, 0xe7, 0xaf, 0x62, 0x06,
0xa2, 0x8f, 0xb5, 0xe8, 0xfc, 0xad, 0x45, 0x1f, 0x5f, 0x27, 0xfa, 0x78, 0x5c, 0x54, 0xc5, 0xe4,
0xcd, 0x3e, 0x51, 0x89, 0x9a, 0x71, 0xfb, 0x66, 0xbf, 0x52, 0xd4, 0xca, 0xc0, 0xa2, 0xe4, 0x7e,
0x02, 0xcb, 0x1e, 0x4d, 0xb8, 0xc8, 0x6d, 0x09, 0x6d, 0x45, 0x44, 0x6b, 0x96, 0xa4, 0xe6, 0xe1,
0x8d, 0x34, 0xef, 0xe9, 0x93, 0x7d, 0x0d, 0x9f, 0x83, 0x96, 0xc6, 0xcd, 0x4a, 0xbd, 0x05, 0xac,
0x16, 0x11, 0x84, 0xf1, 0x66, 0xca, 0x02, 0xad, 0x0c, 0xa4, 0xf2, 0xc1, 0x8d, 0x94, 0xf5, 0x39,
0x98, 0xe4, 0x72, 0x50, 0x75, 0x68, 0x52, 0x8a, 0x3f, 0x80, 0x4a, 0x98, 0x4f, 0xa3, 0x99, 0x46,
0x5a, 0xaf, 0x2c, 0xf5, 0xf6, 0x6e, 0xa4, 0xa7, 0x0f, 0xf3, 0x38, 0x93, 0x83, 0x16, 0xfa, 0x06,
0xa5, 0x95, 0x02, 0x18, 0xa7, 0x21, 0x73, 0x83, 0x08, 0x7b, 0x21, 0x61, 0x5a, 0xcf, 0x94, 0x7a,
0xcf, 0x6f, 0xa4, 0x77, 0x57, 0xe9, 0x5d, 0x65, 0x73, 0x90, 0x95, 0x1b, 0x9f, 0x2b, 0x9b, 0x92,
0xf5, 0x81, 0xd9, 0x24, 0x2c, 0x0a, 0x13, 0x2d, 0xb8, 0x20, 0x05, 0x77, 0x6f, 0x24, 0xa8, 0xfb,
0x74, 0x94, 0xc7, 0x41, 0x65, 0x05, 0x07, 0x2a, 0x11, 0x4d, 0x7c, 0xda, 0x57, 0x59, 0xbc, 0xbd,
0xca, 0x28, 0x8f, 0x83, 0xca, 0x0a, 0x2a, 0x95, 0x0e, 0x58, 0xc2, 0x8c, 0xd1, 0xd7, 0x13, 0x35,
0x84, 0x52, 0xec, 0xc5, 0x8d, 0xc4, 0x56, 0x95, 0xd8, 0x35, 0x74, 0x0e, 0x5a, 0x94, 0xd6, 0xb1,
0x2a, 0x52, 0x60, 0xc5, 0x84, 0x05, 0x64, 0xf4, 0x1e, 0x58, 0xba, 0x7d, 0x6b, 0x4e, 0x72, 0x39,
0xa8, 0x22, 0x4d, 0x83, 0x6f, 0xff, 0x51, 0xd1, 0xa8, 0x58, 0xd5, 0xa3, 0xa2, 0x51, 0xb5, 0xac,
0xa3, 0xa2, 0x61, 0x59, 0x8b, 0x68, 0xa1, 0x4b, 0x23, 0xea, 0xb6, 0x1f, 0xa9, 0x0c, 0x54, 0x26,
0xaf, 0x31, 0xd7, 0x07, 0x19, 0x55, 0x3c, 0x2c, 0x70, 0xd4, 0xe5, 0x42, 0xd3, 0xd5, 0xc1, 0xec,
0x89, 0xc8, 0xdf, 0x05, 0x16, 0x28, 0x9c, 0x93, 0xae, 0xba, 0x20, 0x51, 0x3e, 0x84, 0xcb, 0x60,
0xb6, 0x8d, 0xa3, 0x54, 0x3d, 0x30, 0x4a, 0x48, 0x01, 0xe7, 0x18, 0x54, 0x4f, 0x19, 0x4e, 0x38,
0xf6, 0x44, 0x48, 0x93, 0x97, 0x34, 0xe0, 0x10, 0x82, 0xa2, 0xfc, 0x50, 0xab, 0x5c, 0x39, 0x86,
0x9f, 0x82, 0x62, 0x44, 0x03, 0x5e, 0x9b, 0x59, 0x2f, 0x6c, 0x94, 0xb7, 0xef, 0x5c, 0xbd, 0xe2,
0x5f, 0xd2, 0x00, 0xc9, 0x10, 0xe7, 0x8f, 0x19, 0x50, 0x78, 0x49, 0x03, 0x58, 0x03, 0xf3, 0xd8,
0xf7, 0x19, 0xe1, 0x5c, 0x33, 0xf5, 0x21, 0x5c, 0x01, 0x73, 0x82, 0xb6, 0x42, 0x4f, 0xd1, 0x95,
0x90, 0x46, 0xb9, 0xb0, 0x8f, 0x05, 0x96, 0x57, 0x9d, 0x89, 0xe4, 0x18, 0x6e, 0x03, 0x53, 0xae,
0xcc, 0x4d, 0xd2, 0xb8, 0x49, 0x98, 0xbc, 0xb1, 0x8a, 0x8d, 0xea, 0x65, 0x66, 0x97, 0xa5, 0xfd,
0x2b, 0x69, 0x46, 0xa3, 0x00, 0xde, 0x07, 0xf3, 0xa2, 0x33, 0x7a, 0xd9, 0x2c, 0x5d, 0x66, 0x76,
0x55, 0x0c, 0x97, 0x99, 0xdf, 0x25, 0x68, 0x4e, 0x74, 0xe4, 0x9d, 0x52, 0x07, 0x86, 0xe8, 0xb8,
0x61, 0xe2, 0x93, 0x8e, 0xbc, 0x4f, 0x8a, 0x8d, 0xe5, 0xcb, 0xcc, 0xb6, 0x46, 0xc2, 0x0f, 0x73,
0x1f, 0x9a, 0x17, 0x1d, 0x39, 0x80, 0xf7, 0x01, 0x50, 0x53, 0x92, 0x0a, 0xea, 0x36, 0x58, 0xb8,
0xcc, 0xec, 0x92, 0xb4, 0x4a, 0xee, 0xe1, 0x10, 0x3a, 0x60, 0x56, 0x71, 0x1b, 0x92, 0xdb, 0xbc,
0xcc, 0x6c, 0x23, 0xa2, 0x81, 0xe2, 0x54, 0xae, 0xbc, 0x54, 0x8c, 0xc4, 0xb4, 0x4d, 0x7c, 0xf9,
0xc1, 0x35, 0x50, 0x1f, 0x3a, 0xbf, 0xcc, 0x00, 0xe3, 0xb4, 0x83, 0x08, 0x4f, 0x23, 0x01, 0x9f,
0x01, 0xcb, 0xa3, 0x89, 0x60, 0xd8, 0x13, 0xee, 0x58, 0x69, 0x1b, 0xf7, 0x86, 0x1d, 0x36, 0x19,
0xe1, 0xa0, 0x6a, 0xdf, 0xb4, 0xab, 0xeb, 0xbf, 0x0c, 0x66, 0x9b, 0x11, 0xa5, 0xb1, 0xec, 0x04,
0x13, 0x29, 0x00, 0x91, 0xac, 0x9a, 0xdc, 0xe5, 0x82, 0x7c, 0xc8, 0x7d, 0x74, 0x75, 0x97, 0x27,
0x5a, 0xa5, 0xb1, 0xa2, 0x1f, 0x73, 0x15, 0xa5, 0xad, 0xf3, 0x9d, 0xbc, 0xb6, 0xb2, 0x95, 0x2c,
0x50, 0x60, 0x44, 0xc8, 0x4d, 0x33, 0x51, 0x3e, 0x84, 0xab, 0xc0, 0x60, 0xa4, 0x4d, 0x98, 0x20,
0xbe, 0xdc, 0x1c, 0x03, 0x0d, 0x30, 0xbc, 0x0b, 0x8c, 0x00, 0x73, 0x37, 0xe5, 0xc4, 0x57, 0x3b,
0x81, 0xe6, 0x03, 0xcc, 0xbf, 0xe1, 0xc4, 0x7f, 0x52, 0xfc, 0xf9, 0x37, 0x7b, 0xca, 0xc1, 0xa0,
0xbc, 0xeb, 0x79, 0x84, 0xf3, 0xd3, 0xb4, 0x15, 0x91, 0x7f, 0xe9, 0xb0, 0x6d, 0x60, 0x72, 0x41,
0x19, 0x0e, 0x88, 0x7b, 0x4e, 0xba, 0xba, 0xcf, 0x54, 0xd7, 0x68, 0xfb, 0x17, 0xa4, 0xcb, 0xd1,
0x28, 0xd0, 0x12, 0xef, 0x0a, 0xa0, 0x7c, 0xca, 0xb0, 0x47, 0xf4, 0xa3, 0x33, 0xef, 0xd5, 0x1c,
0x32, 0x2d, 0xa1, 0x51, 0xae, 0x2d, 0xc2, 0x98, 0xd0, 0x54, 0xe8, 0xf3, 0xd4, 0x87, 0x79, 0x06,
0x23, 0xa4, 0x43, 0x3c, 0x59, 0xc6, 0x22, 0xd2, 0x08, 0xee, 0x80, 0x05, 0x3f, 0xe4, 0xf2, 0x35,
0xce, 0x05, 0xf6, 0xce, 0xd5, 0xf2, 0x1b, 0xd6, 0x65, 0x66, 0x9b, 0xda, 0x71, 0x92, 0xdb, 0xd1,
0x18, 0x82, 0x4f, 0x41, 0x75, 0x98, 0x26, 0x67, 0x2b, 0x6b, 0x63, 0x34, 0xe0, 0x65, 0x66, 0x57,
0x06, 0xa1, 0xd2, 0x83, 0x26, 0x70, 0xbe, 0xd3, 0x3e, 0x69, 0xa6, 0x81, 0x6c, 0x3e, 0x03, 0x29,
0x90, 0x5b, 0xa3, 0x30, 0x0e, 0x85, 0x6c, 0xb6, 0x59, 0xa4, 0x00, 0x7c, 0x0a, 0x4a, 0xb4, 0x4d,
0x18, 0x0b, 0x7d, 0xc2, 0xe5, 0xed, 0xfb, 0x5f, 0x4f, 0x79, 0x34, 0x8c, 0xcf, 0x17, 0xa7, 0xff,
0x69, 0xc4, 0x24, 0xa6, 0xac, 0x2b, 0xaf, 0x53, 0xbd, 0x38, 0xe5, 0xf8, 0x52, 0xda, 0xd1, 0x18,
0x82, 0x0d, 0x00, 0x75, 0x1a, 0x23, 0x22, 0x65, 0x89, 0x2b, 0xcf, 0xbf, 0x29, 0x73, 0xe5, 0x29,
0x54, 0x5e, 0x24, 0x9d, 0xfb, 0x58, 0x60, 0x74, 0xc5, 0x72, 0x54, 0x34, 0x8a, 0xd6, 0xec, 0x51,
0xd1, 0x98, 0xb7, 0x8c, 0xc1, 0xfa, 0xf5, 0x2c, 0xd0, 0x52, 0x1f, 0x8f, 0xd0, 0x37, 0x76, 0xdf,
0x5c, 0xac, 0x4d, 0xbf, 0xbd, 0x58, 0x9b, 0x7e, 0x77, 0xb1, 0x36, 0xfd, 0xeb, 0xfb, 0xb5, 0xa9,
0xb7, 0xef, 0xd7, 0xa6, 0xfe, 0x7a, 0xbf, 0x36, 0xf5, 0xdd, 0x27, 0xa3, 0x9f, 0x73, 0xc2, 0xbc,
0x07, 0x21, 0xad, 0x47, 0xd8, 0xa3, 0x49, 0xe8, 0xf9, 0xf5, 0x8e, 0xfc, 0x87, 0x28, 0xbf, 0xe9,
0xcd, 0x39, 0xf9, 0xcf, 0xef, 0xd1, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x53, 0x5a, 0xaa, 0xda,
0x3f, 0x0e, 0x00, 0x00,
// 1538 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0x5d, 0x4f, 0xdc, 0xca,
0x19, 0x06, 0x76, 0x01, 0xef, 0xec, 0xb2, 0x6b, 0x86, 0x85, 0x6e, 0x88, 0x8a, 0xa9, 0x2f, 0x2a,
0x2a, 0x25, 0x10, 0x88, 0x50, 0xa3, 0x44, 0x95, 0xca, 0x02, 0x49, 0xa0, 0x69, 0x8a, 0x06, 0xa2,
0x4a, 0x95, 0x2a, 0x6b, 0xd6, 0x9e, 0x18, 0x17, 0xdb, 0xb3, 0x9a, 0x19, 0x6f, 0x76, 0xdb, 0xfe,
0x80, 0x56, 0xbd, 0xe9, 0x4f, 0xe8, 0xcf, 0x89, 0xaa, 0x5e, 0xe4, 0xb2, 0x3a, 0x17, 0x56, 0x44,
0xee, 0xb8, 0xdc, 0x5f, 0x70, 0x34, 0x1f, 0xfb, 0x09, 0x3a, 0xe7, 0xc0, 0x95, 0xe7, 0x79, 0x3f,
0x9e, 0x67, 0x3e, 0x5e, 0xfb, 0x1d, 0x83, 0x75, 0x22, 0x2e, 0x09, 0x4b, 0xa2, 0x54, 0xec, 0x90,
0x4e, 0xb2, 0xd3, 0xd9, 0x95, 0x8f, 0xed, 0x36, 0xa3, 0x82, 0x42, 0x7b, 0xe8, 0xdb, 0x96, 0xc6,
0xce, 0xee, 0x7a, 0x3d, 0xa4, 0x21, 0x55, 0xce, 0x1d, 0x39, 0xd2, 0x71, 0xee, 0x3f, 0x0b, 0x60,
0xe1, 0x0c, 0x33, 0x9c, 0x70, 0xb8, 0x0b, 0x4a, 0xa4, 0x93, 0x78, 0x01, 0x49, 0x69, 0xd2, 0x98,
0xdd, 0x9c, 0xdd, 0x2a, 0x35, 0xeb, 0xfd, 0xdc, 0xb1, 0x7b, 0x38, 0x89, 0x5f, 0xba, 0x43, 0x97,
0x8b, 0x2c, 0xd2, 0x49, 0x8e, 0xe4, 0x10, 0xfe, 0x06, 0x2c, 0x91, 0x14, 0xb7, 0x62, 0xe2, 0xf9,
0x8c, 0x60, 0x41, 0x1a, 0x73, 0x9b, 0xb3, 0x5b, 0x56, 0xb3, 0xd1, 0xcf, 0x9d, 0xba, 0x49, 0x1b,
0x77, 0xbb, 0xa8, 0xa2, 0xf1, 0xa1, 0x82, 0xf0, 0xd7, 0xa0, 0x3c, 0xf0, 0xe3, 0x38, 0x6e, 0x14,
0x54, 0xf2, 0x5a, 0x3f, 0x77, 0xe0, 0x64, 0x32, 0x8e, 0x63, 0x17, 0x01, 0x93, 0x8a, 0xe3, 0x18,
0x1e, 0x00, 0x40, 0xba, 0x82, 0x61, 0x8f, 0x44, 0x6d, 0xde, 0x28, 0x6e, 0x16, 0xb6, 0x0a, 0x4d,
0xf7, 0x3a, 0x77, 0x4a, 0xc7, 0xd2, 0x7a, 0x7c, 0x72, 0xc6, 0xfb, 0xb9, 0xb3, 0x6c, 0x48, 0x86,
0x81, 0x2e, 0x2a, 0x29, 0x70, 0x1c, 0xb5, 0x39, 0xfc, 0x33, 0xa8, 0xf8, 0x97, 0x38, 0x4a, 0x3d,
0x9f, 0xa6, 0x1f, 0xa3, 0xb0, 0x31, 0xbf, 0x39, 0xbb, 0x55, 0xde, 0xfb, 0xf9, 0xf6, 0xf4, 0xbe,
0x6d, 0x1f, 0xca, 0xa8, 0x43, 0x15, 0xd4, 0x7c, 0xfc, 0x39, 0x77, 0x66, 0xfa, 0xb9, 0xb3, 0xa2,
0xa9, 0xc7, 0x09, 0x5c, 0x54, 0xf6, 0x47, 0x91, 0x70, 0x0f, 0xac, 0xe2, 0x38, 0xa6, 0x9f, 0xbc,
0x2c, 0x95, 0x1b, 0x4d, 0x7c, 0x41, 0x02, 0x4f, 0x74, 0x79, 0x63, 0x41, 0x2e, 0x12, 0xad, 0x28,
0xe7, 0x87, 0x91, 0xef, 0xa2, 0xcb, 0xdd, 0xff, 0xd5, 0x40, 0x79, 0x4c, 0x0d, 0x26, 0xa0, 0x76,
0x49, 0x13, 0xc2, 0x05, 0xc1, 0x81, 0xd7, 0x8a, 0xa9, 0x7f, 0x65, 0x8e, 0xe5, 0xe8, 0xbb, 0xdc,
0xf9, 0x65, 0x18, 0x89, 0xcb, 0xac, 0xb5, 0xed, 0xd3, 0x64, 0xc7, 0xa7, 0x3c, 0xa1, 0xdc, 0x3c,
0x9e, 0xf2, 0xe0, 0x6a, 0x47, 0xf4, 0xda, 0x84, 0x6f, 0x9f, 0xa4, 0xa2, 0x9f, 0x3b, 0x6b, 0x7a,
0xb2, 0x53, 0x54, 0x2e, 0xaa, 0x0e, 0x2d, 0x4d, 0x69, 0x80, 0x3d, 0x50, 0x0d, 0x30, 0xf5, 0x3e,
0x52, 0x76, 0x65, 0xd4, 0xe6, 0x94, 0xda, 0xf9, 0x4f, 0x57, 0xbb, 0xce, 0x9d, 0xca, 0xd1, 0xc1,
0x1f, 0x5e, 0x53, 0x76, 0xa5, 0x38, 0xfb, 0xb9, 0xb3, 0xaa, 0xd5, 0x27, 0x99, 0x5d, 0x54, 0x09,
0x30, 0x1d, 0x86, 0xc1, 0x3f, 0x02, 0x7b, 0x18, 0xc0, 0xb3, 0x76, 0x9b, 0x32, 0x61, 0xaa, 0xe1,
0xe9, 0x75, 0xee, 0x54, 0x0d, 0xe5, 0xb9, 0xf6, 0xf4, 0x73, 0xe7, 0x67, 0x53, 0xa4, 0x26, 0xc7,
0x45, 0x55, 0x43, 0x6b, 0x42, 0x21, 0x07, 0x15, 0x12, 0xb5, 0x77, 0xf7, 0x9f, 0x99, 0x15, 0x15,
0xd5, 0x8a, 0xce, 0xee, 0xb5, 0xa2, 0xf2, 0xf1, 0xc9, 0xd9, 0xee, 0xfe, 0xb3, 0xc1, 0x82, 0xcc,
0xd9, 0x8f, 0xd3, 0xba, 0xa8, 0xac, 0xa1, 0x5e, 0xcd, 0x09, 0x30, 0xd0, 0xbb, 0xc4, 0xfc, 0x52,
0x55, 0x56, 0xa9, 0xb9, 0x75, 0x9d, 0x3b, 0x40, 0x33, 0xbd, 0xc5, 0xfc, 0x72, 0x74, 0x2e, 0xad,
0xde, 0x5f, 0x71, 0x2a, 0xa2, 0x2c, 0x19, 0x70, 0x01, 0x9d, 0x2c, 0xa3, 0x86, 0xf3, 0xdf, 0x37,
0xf3, 0x5f, 0x78, 0xf0, 0xfc, 0xf7, 0xef, 0x9a, 0xff, 0xfe, 0xe4, 0xfc, 0x75, 0xcc, 0x50, 0xf4,
0x85, 0x11, 0x5d, 0x7c, 0xb0, 0xe8, 0x8b, 0xbb, 0x44, 0x5f, 0x4c, 0x8a, 0xea, 0x18, 0x59, 0xec,
0x53, 0x3b, 0xd1, 0xb0, 0x1e, 0x5e, 0xec, 0xb7, 0x36, 0xb5, 0x3a, 0xb4, 0x68, 0xb9, 0xbf, 0x83,
0xba, 0x4f, 0x53, 0x2e, 0xa4, 0x2d, 0xa5, 0xed, 0x98, 0x18, 0xcd, 0x92, 0xd2, 0x3c, 0xb9, 0x97,
0xe6, 0x63, 0xf3, 0x35, 0xb8, 0x83, 0xcf, 0x45, 0x2b, 0x93, 0x66, 0xad, 0xde, 0x06, 0x76, 0x9b,
0x08, 0xc2, 0x78, 0x2b, 0x63, 0xa1, 0x51, 0x06, 0x4a, 0xf9, 0xf8, 0x5e, 0xca, 0xe6, 0x3d, 0x98,
0xe6, 0x72, 0x51, 0x6d, 0x64, 0xd2, 0x8a, 0x7f, 0x01, 0xd5, 0x48, 0x4e, 0xa3, 0x95, 0xc5, 0x46,
0xaf, 0xac, 0xf4, 0x0e, 0xef, 0xa5, 0x67, 0x5e, 0xe6, 0x49, 0x26, 0x17, 0x2d, 0x0d, 0x0c, 0x5a,
0x2b, 0x03, 0x30, 0xc9, 0x22, 0xe6, 0x85, 0x31, 0xf6, 0x23, 0xc2, 0x8c, 0x5e, 0x45, 0xe9, 0xbd,
0xb9, 0x97, 0xde, 0x23, 0xad, 0x77, 0x9b, 0xcd, 0x45, 0xb6, 0x34, 0xbe, 0xd1, 0x36, 0x2d, 0x1b,
0x80, 0x4a, 0x8b, 0xb0, 0x38, 0x4a, 0x8d, 0xe0, 0x92, 0x12, 0x3c, 0xb8, 0x97, 0xa0, 0xa9, 0xd3,
0x71, 0x1e, 0x17, 0x95, 0x35, 0x1c, 0xaa, 0xc4, 0x34, 0x0d, 0xe8, 0x40, 0x65, 0xf9, 0xe1, 0x2a,
0xe3, 0x3c, 0x2e, 0x2a, 0x6b, 0xa8, 0x55, 0xba, 0x60, 0x05, 0x33, 0x46, 0x3f, 0x4d, 0xed, 0x21,
0x54, 0x62, 0x6f, 0xef, 0x25, 0xb6, 0xae, 0xc5, 0xee, 0xa0, 0x73, 0xd1, 0xb2, 0xb2, 0x4e, 0xec,
0x62, 0x06, 0x60, 0xc8, 0x70, 0x6f, 0x4a, 0xb8, 0xfe, 0xf0, 0xc3, 0xbb, 0xcd, 0xe6, 0x22, 0x5b,
0x1a, 0x27, 0x64, 0xff, 0x06, 0xea, 0x09, 0x61, 0x21, 0xf1, 0x52, 0x22, 0x78, 0x3b, 0x8e, 0x84,
0x11, 0x5e, 0x7d, 0xf8, 0xfb, 0x78, 0x17, 0x9f, 0x8b, 0xa0, 0x32, 0xbf, 0x37, 0x56, 0x25, 0x7e,
0x5a, 0xb4, 0xaa, 0x76, 0xed, 0xb4, 0x68, 0xd5, 0x6c, 0xfb, 0xb4, 0x68, 0xd9, 0xf6, 0xf2, 0x69,
0xd1, 0x5a, 0xb1, 0xeb, 0x68, 0xa9, 0x47, 0x63, 0xea, 0x75, 0x9e, 0xeb, 0x5c, 0x54, 0x26, 0x9f,
0x30, 0x37, 0x5f, 0x14, 0x54, 0xf5, 0xb1, 0xc0, 0x71, 0x8f, 0x1b, 0x62, 0x64, 0x6b, 0xb9, 0xb1,
0x1e, 0xb7, 0x03, 0xe6, 0xcf, 0x85, 0xbc, 0xe6, 0xd8, 0xa0, 0x70, 0x45, 0x7a, 0xba, 0x77, 0x23,
0x39, 0x84, 0x75, 0x30, 0xdf, 0xc1, 0x71, 0xa6, 0xef, 0x4b, 0x25, 0xa4, 0x81, 0x7b, 0x06, 0x6a,
0x17, 0x0c, 0xa7, 0x1c, 0xfb, 0x22, 0xa2, 0xe9, 0x3b, 0x1a, 0x72, 0x08, 0x41, 0x51, 0xf5, 0x10,
0x9d, 0xab, 0xc6, 0xf0, 0x57, 0xa0, 0x18, 0xd3, 0x90, 0x37, 0xe6, 0x36, 0x0b, 0x5b, 0xe5, 0xbd,
0xd5, 0xdb, 0x37, 0x96, 0x77, 0x34, 0x44, 0x2a, 0xc4, 0xfd, 0xef, 0x1c, 0x28, 0xbc, 0xa3, 0x21,
0x6c, 0x80, 0x45, 0x1c, 0x04, 0x8c, 0x70, 0x6e, 0x98, 0x06, 0x10, 0xae, 0x81, 0x05, 0x41, 0xdb,
0x91, 0xaf, 0xe9, 0x4a, 0xc8, 0x20, 0x29, 0x1c, 0x60, 0x81, 0x55, 0x17, 0xae, 0x20, 0x35, 0x86,
0x7b, 0xa0, 0xa2, 0x56, 0xe6, 0xa5, 0x59, 0xd2, 0x22, 0x4c, 0x35, 0xd3, 0x62, 0xb3, 0x76, 0x93,
0x3b, 0x65, 0x65, 0x7f, 0xaf, 0xcc, 0x68, 0x1c, 0xc0, 0x27, 0x60, 0x51, 0x74, 0xc7, 0xfb, 0xe0,
0xca, 0x4d, 0xee, 0xd4, 0xc4, 0x68, 0x99, 0xb2, 0xcd, 0xa1, 0x05, 0xd1, 0x55, 0xed, 0x6e, 0x07,
0x58, 0xa2, 0xeb, 0x45, 0x69, 0x40, 0xba, 0xaa, 0xd5, 0x15, 0x9b, 0xf5, 0x9b, 0xdc, 0xb1, 0xc7,
0xc2, 0x4f, 0xa4, 0x0f, 0x2d, 0x8a, 0xae, 0x1a, 0xc0, 0x27, 0x00, 0xe8, 0x29, 0x29, 0x05, 0xdd,
0xa8, 0x96, 0x6e, 0x72, 0xa7, 0xa4, 0xac, 0x8a, 0x7b, 0x34, 0x84, 0x2e, 0x98, 0xd7, 0xdc, 0x96,
0xe2, 0xae, 0xdc, 0xe4, 0x8e, 0x15, 0xd3, 0x50, 0x73, 0x6a, 0x97, 0xdc, 0x2a, 0x46, 0x12, 0xda,
0x21, 0x81, 0xea, 0x05, 0x16, 0x1a, 0x40, 0xf7, 0x5f, 0x73, 0xc0, 0xba, 0xe8, 0x22, 0xc2, 0xb3,
0x58, 0xc0, 0xd7, 0xc0, 0xf6, 0x69, 0x2a, 0x18, 0xf6, 0x85, 0x37, 0xb1, 0xb5, 0xcd, 0xc7, 0xa3,
0xef, 0xf2, 0x74, 0x84, 0x8b, 0x6a, 0x03, 0xd3, 0x81, 0xd9, 0xff, 0x3a, 0x98, 0x6f, 0xc5, 0x94,
0x26, 0xaa, 0x12, 0x2a, 0x48, 0x03, 0x88, 0xd4, 0xae, 0xa9, 0x53, 0x2e, 0xa8, 0x7b, 0xe9, 0x2f,
0x6e, 0x9f, 0xf2, 0x54, 0xa9, 0x34, 0xd7, 0xcc, 0xdd, 0xb4, 0xaa, 0xb5, 0x4d, 0xbe, 0x2b, 0xf7,
0x56, 0x95, 0x92, 0x0d, 0x0a, 0x8c, 0x08, 0x75, 0x68, 0x15, 0x24, 0x87, 0x70, 0x1d, 0x58, 0x8c,
0x74, 0x08, 0x13, 0x24, 0x50, 0x87, 0x63, 0xa1, 0x21, 0x86, 0x8f, 0x80, 0x15, 0x62, 0xee, 0x65,
0x9c, 0x04, 0xfa, 0x24, 0xd0, 0x62, 0x88, 0xf9, 0x07, 0x4e, 0x82, 0x97, 0xc5, 0x7f, 0xfc, 0xc7,
0x99, 0x71, 0x31, 0x28, 0x1f, 0xf8, 0x3e, 0xe1, 0xfc, 0x22, 0x6b, 0xc7, 0xe4, 0x07, 0x2a, 0x6c,
0x0f, 0x54, 0xb8, 0xa0, 0x0c, 0x87, 0xc4, 0xbb, 0x22, 0x3d, 0x53, 0x67, 0xba, 0x6a, 0x8c, 0xfd,
0x77, 0xa4, 0xc7, 0xd1, 0x38, 0x30, 0x12, 0x5f, 0x0b, 0xa0, 0x7c, 0xc1, 0xb0, 0x4f, 0xcc, 0x7d,
0x58, 0xd6, 0xaa, 0x84, 0xcc, 0x48, 0x18, 0x24, 0xb5, 0x45, 0x94, 0x10, 0x9a, 0x09, 0xf3, 0x3e,
0x0d, 0xa0, 0xcc, 0x60, 0x84, 0x74, 0x89, 0xaf, 0xb6, 0xb1, 0x88, 0x0c, 0x82, 0xfb, 0x60, 0x29,
0x88, 0xb8, 0xfa, 0xb9, 0xe0, 0x02, 0xfb, 0x57, 0x7a, 0xf9, 0x4d, 0xfb, 0x26, 0x77, 0x2a, 0xc6,
0x71, 0x2e, 0xed, 0x68, 0x02, 0xc1, 0x57, 0xa0, 0x36, 0x4a, 0x53, 0xb3, 0xd5, 0xd7, 0xf9, 0x26,
0xbc, 0xc9, 0x9d, 0xea, 0x30, 0x54, 0x79, 0xd0, 0x14, 0x96, 0x27, 0x1d, 0x90, 0x56, 0x16, 0xaa,
0xe2, 0xb3, 0x90, 0x06, 0xd2, 0x1a, 0x47, 0x49, 0x24, 0x54, 0xb1, 0xcd, 0x23, 0x0d, 0xe0, 0x2b,
0x50, 0xa2, 0x1d, 0xc2, 0x58, 0x14, 0x10, 0xae, 0x2e, 0x06, 0x3f, 0xf6, 0x67, 0x82, 0x46, 0xf1,
0x72, 0x71, 0xe6, 0xc7, 0x29, 0x21, 0x09, 0x65, 0x3d, 0xd5, 0xe9, 0xcd, 0xe2, 0xb4, 0xe3, 0xf7,
0xca, 0x8e, 0x26, 0x10, 0x6c, 0x02, 0x68, 0xd2, 0x18, 0x11, 0x19, 0x4b, 0x3d, 0xf5, 0xfe, 0x57,
0x54, 0xae, 0x7a, 0x0b, 0xb5, 0x17, 0x29, 0xe7, 0x11, 0x16, 0x18, 0xdd, 0xb2, 0x9c, 0x16, 0xad,
0xa2, 0x3d, 0x7f, 0x5a, 0xb4, 0x16, 0x6d, 0x6b, 0xb8, 0x7e, 0x33, 0x0b, 0xb4, 0x32, 0xc0, 0x63,
0xf4, 0xcd, 0xdf, 0x7e, 0xbe, 0xde, 0x98, 0xfd, 0x72, 0xbd, 0x31, 0xfb, 0xf5, 0x7a, 0x63, 0xf6,
0xdf, 0xdf, 0x36, 0x66, 0xbe, 0x7c, 0xdb, 0x98, 0xf9, 0xff, 0xb7, 0x8d, 0x99, 0x3f, 0x8d, 0x7f,
0xee, 0x49, 0x47, 0x7e, 0xed, 0x47, 0x7f, 0xbb, 0x5d, 0xf5, 0xbf, 0xab, 0x3e, 0xf9, 0xad, 0x05,
0xf5, 0x1f, 0xfb, 0xfc, 0xfb, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfb, 0x44, 0xf1, 0x35, 0x0d, 0x0f,
0x00, 0x00,
}
func (m *Params) Marshal() (dAtA []byte, err error) {
@@ -773,6 +789,16 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if m.AllowUnprotectedTxs {
i--
if m.AllowUnprotectedTxs {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x30
}
{
size, err := m.ChainConfig.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
@@ -852,11 +878,11 @@ func (m *ChainConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if m.MergeForkBlock != nil {
if m.MergeNetsplitBlock != nil {
{
size := m.MergeForkBlock.Size()
size := m.MergeNetsplitBlock.Size()
i -= size
if _, err := m.MergeForkBlock.MarshalTo(dAtA[i:]); err != nil {
if _, err := m.MergeNetsplitBlock.MarshalTo(dAtA[i:]); err != nil {
return 0, err
}
i = encodeVarintEvm(dAtA, i, uint64(size))
@@ -864,7 +890,21 @@ func (m *ChainConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i--
dAtA[i] = 0x1
i--
dAtA[i] = 0x9a
dAtA[i] = 0xaa
}
if m.GrayGlacierBlock != nil {
{
size := m.GrayGlacierBlock.Size()
i -= size
if _, err := m.GrayGlacierBlock.MarshalTo(dAtA[i:]); err != nil {
return 0, err
}
i = encodeVarintEvm(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x1
i--
dAtA[i] = 0xa2
}
if m.ArrowGlacierBlock != nil {
{
@@ -1465,6 +1505,9 @@ func (m *Params) Size() (n int) {
}
l = m.ChainConfig.Size()
n += 1 + l + sovEvm(uint64(l))
if m.AllowUnprotectedTxs {
n += 2
}
return n
}
@@ -1533,8 +1576,12 @@ func (m *ChainConfig) Size() (n int) {
l = m.ArrowGlacierBlock.Size()
n += 2 + l + sovEvm(uint64(l))
}
if m.MergeForkBlock != nil {
l = m.MergeForkBlock.Size()
if m.GrayGlacierBlock != nil {
l = m.GrayGlacierBlock.Size()
n += 2 + l + sovEvm(uint64(l))
}
if m.MergeNetsplitBlock != nil {
l = m.MergeNetsplitBlock.Size()
n += 2 + l + sovEvm(uint64(l))
}
return n
@@ -1925,6 +1972,26 @@ func (m *Params) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 6:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field AllowUnprotectedTxs", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowEvm
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.AllowUnprotectedTxs = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipEvm(dAtA[iNdEx:])
@@ -2495,9 +2562,9 @@ func (m *ChainConfig) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 19:
case 20:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field MergeForkBlock", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field GrayGlacierBlock", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
@@ -2526,8 +2593,44 @@ func (m *ChainConfig) Unmarshal(dAtA []byte) error {
return io.ErrUnexpectedEOF
}
var v github_com_cosmos_cosmos_sdk_types.Int
m.MergeForkBlock = &v
if err := m.MergeForkBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
m.GrayGlacierBlock = &v
if err := m.GrayGlacierBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 21:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field MergeNetsplitBlock", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowEvm
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthEvm
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthEvm
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
var v github_com_cosmos_cosmos_sdk_types.Int
m.MergeNetsplitBlock = &v
if err := m.MergeNetsplitBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
+20 -21
View File
@@ -152,27 +152,26 @@ func init() {
func init() { proto.RegisterFile("ethermint/evm/v1/genesis.proto", fileDescriptor_9bcdec50cc9d156d) }
var fileDescriptor_9bcdec50cc9d156d = []byte{
// 308 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xb1, 0x4e, 0xf3, 0x30,
0x14, 0x85, 0xe3, 0xbf, 0x55, 0xfb, 0xd7, 0x45, 0x80, 0x2c, 0x24, 0xa2, 0x0e, 0x6e, 0xd5, 0x85,
0x2e, 0xd8, 0x6a, 0x91, 0xd8, 0x9b, 0x85, 0x15, 0xa5, 0x1b, 0x9b, 0xeb, 0x5c, 0xa5, 0x91, 0x48,
0x5c, 0xd9, 0x6e, 0x04, 0x2b, 0x23, 0x13, 0xcf, 0xc1, 0x93, 0x74, 0xec, 0xc8, 0x04, 0xa8, 0x79,
0x11, 0x14, 0x27, 0xad, 0x04, 0xd9, 0xae, 0x75, 0xbe, 0x73, 0xce, 0xf5, 0xc5, 0x14, 0xec, 0x0a,
0x74, 0x9a, 0x64, 0x96, 0x43, 0x9e, 0xf2, 0x7c, 0xca, 0x63, 0xc8, 0xc0, 0x24, 0x86, 0xad, 0xb5,
0xb2, 0x8a, 0x9c, 0x1f, 0x75, 0x06, 0x79, 0xca, 0xf2, 0xe9, 0xe0, 0x22, 0x56, 0xb1, 0x72, 0x22,
0x2f, 0xa7, 0x8a, 0x1b, 0x0c, 0x1a, 0x39, 0x25, 0xee, 0xb4, 0xf1, 0x2b, 0xc2, 0x27, 0x77, 0x55,
0xea, 0xc2, 0x0a, 0x0b, 0x24, 0xc0, 0xff, 0x85, 0x94, 0x6a, 0x93, 0x59, 0xe3, 0xa3, 0x51, 0x6b,
0xd2, 0x9f, 0x8d, 0xd8, 0xdf, 0x1e, 0x56, 0x3b, 0xe6, 0x15, 0x18, 0xb4, 0xb7, 0x9f, 0x43, 0x2f,
0x3c, 0xfa, 0xc8, 0x2d, 0xee, 0xac, 0x85, 0x16, 0xa9, 0xf1, 0xff, 0x8d, 0xd0, 0xa4, 0x3f, 0xf3,
0x9b, 0x09, 0xf7, 0x4e, 0xaf, 0x9d, 0x35, 0x3d, 0x7e, 0x41, 0xf8, 0xf4, 0x77, 0x34, 0xf1, 0x71,
0x57, 0x44, 0x91, 0x06, 0x53, 0x6e, 0x83, 0x26, 0xbd, 0xf0, 0xf0, 0x24, 0x04, 0xb7, 0xa5, 0x8a,
0xc0, 0x55, 0xf4, 0x42, 0x37, 0x93, 0x00, 0x77, 0x8d, 0x55, 0x5a, 0xc4, 0xe0, 0xb7, 0xdc, 0xee,
0x97, 0xcd, 0x66, 0xf7, 0xcd, 0xe0, 0xac, 0x2c, 0x7e, 0xff, 0x1a, 0x76, 0x17, 0x15, 0x1f, 0x1e,
0x8c, 0xc1, 0x7c, 0xbb, 0xa7, 0x68, 0xb7, 0xa7, 0xe8, 0x7b, 0x4f, 0xd1, 0x5b, 0x41, 0xbd, 0x5d,
0x41, 0xbd, 0x8f, 0x82, 0x7a, 0x0f, 0x57, 0x71, 0x62, 0x57, 0x9b, 0x25, 0x93, 0x2a, 0xe5, 0x12,
0xb4, 0xbc, 0x4e, 0x14, 0x7f, 0x14, 0x52, 0x65, 0x89, 0x8c, 0xf8, 0x93, 0xbb, 0xad, 0x7d, 0x5e,
0x83, 0x59, 0x76, 0xdc, 0x6d, 0x6f, 0x7e, 0x02, 0x00, 0x00, 0xff, 0xff, 0x50, 0xbd, 0xc3, 0x62,
0xc1, 0x01, 0x00, 0x00,
// 297 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x50, 0xbf, 0x4e, 0x83, 0x40,
0x18, 0xe7, 0x6c, 0x53, 0xec, 0xd5, 0xa8, 0xb9, 0x98, 0x48, 0x18, 0xae, 0xa4, 0x83, 0x61, 0x3a,
0xd2, 0x9a, 0x38, 0x2b, 0x8b, 0xab, 0xa1, 0x9b, 0xdb, 0x15, 0xbe, 0x50, 0x06, 0x38, 0xc2, 0x5d,
0x89, 0xae, 0x8e, 0x4e, 0x3e, 0x87, 0x4f, 0xd2, 0xb1, 0xa3, 0x93, 0x1a, 0x78, 0x11, 0xc3, 0x41,
0x6b, 0x94, 0xed, 0xbb, 0xfc, 0xfe, 0xde, 0x0f, 0x53, 0x50, 0x6b, 0x28, 0xd2, 0x24, 0x53, 0x1e,
0x94, 0xa9, 0x57, 0xce, 0xbd, 0x18, 0x32, 0x90, 0x89, 0x64, 0x79, 0x21, 0x94, 0x20, 0xe7, 0x07,
0x9c, 0x41, 0x99, 0xb2, 0x72, 0x6e, 0x5f, 0xc4, 0x22, 0x16, 0x1a, 0xf4, 0x9a, 0xab, 0xe5, 0xd9,
0x76, 0xcf, 0xa7, 0xa1, 0x6b, 0x6c, 0xf6, 0x8a, 0xf0, 0xc9, 0x7d, 0xeb, 0xba, 0x54, 0x5c, 0x01,
0xf1, 0xf1, 0x31, 0x0f, 0x43, 0xb1, 0xc9, 0x94, 0xb4, 0x90, 0x33, 0x70, 0x27, 0x0b, 0x87, 0xfd,
0xcf, 0x61, 0x9d, 0xe2, 0xae, 0x25, 0xfa, 0xc3, 0xed, 0xe7, 0xd4, 0x08, 0x0e, 0x3a, 0x72, 0x83,
0x47, 0x39, 0x2f, 0x78, 0x2a, 0xad, 0x23, 0x07, 0xb9, 0x93, 0x85, 0xd5, 0x77, 0x78, 0xd0, 0x78,
0xa7, 0xec, 0xd8, 0xb3, 0x17, 0x84, 0x4f, 0xff, 0x5a, 0x13, 0x0b, 0x9b, 0x3c, 0x8a, 0x0a, 0x90,
0x4d, 0x1b, 0xe4, 0x8e, 0x83, 0xfd, 0x93, 0x10, 0x3c, 0x0c, 0x45, 0x04, 0x3a, 0x62, 0x1c, 0xe8,
0x9b, 0xf8, 0xd8, 0x94, 0x4a, 0x14, 0x3c, 0x06, 0x6b, 0xa0, 0xbb, 0x5f, 0xf6, 0x93, 0xf5, 0x37,
0xfd, 0xb3, 0x26, 0xf8, 0xfd, 0x6b, 0x6a, 0x2e, 0x5b, 0x7e, 0xb0, 0x17, 0xfa, 0xb7, 0xdb, 0x8a,
0xa2, 0x5d, 0x45, 0xd1, 0x77, 0x45, 0xd1, 0x5b, 0x4d, 0x8d, 0x5d, 0x4d, 0x8d, 0x8f, 0x9a, 0x1a,
0x8f, 0x57, 0x71, 0xa2, 0xd6, 0x9b, 0x15, 0x0b, 0x45, 0xda, 0x2c, 0x28, 0xa4, 0xf7, 0x3b, 0xec,
0x93, 0x9e, 0x56, 0x3d, 0xe7, 0x20, 0x57, 0x23, 0x3d, 0xed, 0xf5, 0x4f, 0x00, 0x00, 0x00, 0xff,
0xff, 0x0a, 0xad, 0x92, 0x3a, 0xc0, 0x01, 0x00, 0x00,
}
func (m *GenesisState) Marshal() (dAtA []byte, err error) {
+5
View File
@@ -115,6 +115,11 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
genState: &GenesisState{},
expPass: false,
},
{
name: "copied genesis",
genState: NewGenesisState(DefaultGenesisState().Params, DefaultGenesisState().Accounts),
expPass: true,
},
{
name: "invalid genesis",
genState: &GenesisState{
+4 -5
View File
@@ -6,9 +6,9 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/ethereum/go-ethereum/common"
feemarkettypes "github.com/cerc-io/laconicd/x/feemarket/types"
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
@@ -27,13 +27,11 @@ type AccountKeeper interface {
// BankKeeper defines the expected interface needed to retrieve account balances.
type BankKeeper interface {
authtypes.BankKeeper
GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
// SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amount sdk.Coins) error
}
// StakingKeeper returns the historical headers kept in store.
@@ -46,6 +44,7 @@ type StakingKeeper interface {
type FeeMarketKeeper interface {
GetBaseFee(ctx sdk.Context) *big.Int
GetParams(ctx sdk.Context) feemarkettypes.Params
AddTransientGasWanted(ctx sdk.Context, gasWanted uint64) (uint64, error)
}
// Event Hooks
@@ -54,5 +53,5 @@ type FeeMarketKeeper interface {
// EvmHooks event hooks for evm tx processing
type EvmHooks interface {
// Must be called after tx is processed successfully, if return an error, the whole transaction is reverted.
PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error
PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error
}
+10 -5
View File
@@ -22,7 +22,7 @@ func newLegacyTx(tx *ethtypes.Transaction) (*LegacyTx, error) {
}
if tx.Value() != nil {
amountInt, err := SafeNewIntFromBigInt(tx.Value())
amountInt, err := types.SafeNewIntFromBigInt(tx.Value())
if err != nil {
return nil, err
}
@@ -30,7 +30,7 @@ func newLegacyTx(tx *ethtypes.Transaction) (*LegacyTx, error) {
}
if tx.GasPrice() != nil {
gasPriceInt, err := SafeNewIntFromBigInt(tx.GasPrice())
gasPriceInt, err := types.SafeNewIntFromBigInt(tx.GasPrice())
if err != nil {
return nil, err
}
@@ -166,10 +166,10 @@ func (tx LegacyTx) Validate() error {
if gasPrice.Sign() == -1 {
return sdkerrors.Wrapf(ErrInvalidGasPrice, "gas price cannot be negative %s", gasPrice)
}
if !IsValidInt256(gasPrice) {
if !types.IsValidInt256(gasPrice) {
return sdkerrors.Wrap(ErrInvalidGasPrice, "out of bound")
}
if !IsValidInt256(tx.Fee()) {
if !types.IsValidInt256(tx.Fee()) {
return sdkerrors.Wrap(ErrInvalidGasFee, "out of bound")
}
@@ -178,7 +178,7 @@ func (tx LegacyTx) Validate() error {
if amount != nil && amount.Sign() == -1 {
return sdkerrors.Wrapf(ErrInvalidAmount, "amount cannot be negative %s", amount)
}
if !IsValidInt256(amount) {
if !types.IsValidInt256(amount) {
return sdkerrors.Wrap(ErrInvalidAmount, "out of bound")
}
@@ -201,6 +201,11 @@ func (tx LegacyTx) Cost() *big.Int {
return cost(tx.Fee(), tx.GetValue())
}
// EffectiveGasPrice is the same as GasPrice for LegacyTx
func (tx LegacyTx) EffectiveGasPrice(baseFee *big.Int) *big.Int {
return tx.GetGasPrice()
}
// EffectiveFee is the same as Fee for LegacyTx
func (tx LegacyTx) EffectiveFee(baseFee *big.Int) *big.Int {
return tx.Fee()
+77 -2
View File
@@ -349,9 +349,84 @@ func (suite *TxDataTestSuite) TestLegacyTxValidate() {
}
}
func (suite *TxDataTestSuite) TestLegacyTxEffectiveGasPrice() {
testCases := []struct {
name string
tx LegacyTx
baseFee *big.Int
exp *big.Int
}{
{
"non-empty legacy tx",
LegacyTx{
GasPrice: &suite.sdkInt,
},
(&suite.sdkInt).BigInt(),
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.EffectiveGasPrice(tc.baseFee)
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestLegacyTxEffectiveFee() {
testCases := []struct {
name string
tx LegacyTx
baseFee *big.Int
exp *big.Int
}{
{
"non-empty legacy tx",
LegacyTx{
GasPrice: &suite.sdkInt,
GasLimit: uint64(1),
},
(&suite.sdkInt).BigInt(),
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.EffectiveFee(tc.baseFee)
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestLegacyTxEffectiveCost() {
testCases := []struct {
name string
tx LegacyTx
baseFee *big.Int
exp *big.Int
}{
{
"non-empty legacy tx",
LegacyTx{
GasPrice: &suite.sdkInt,
GasLimit: uint64(1),
Amount: &suite.sdkZeroInt,
},
(&suite.sdkInt).BigInt(),
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.EffectiveCost(tc.baseFee)
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestLegacyTxFeeCost() {
tx := &LegacyTx{}
suite.Require().Panics(func() { tx.Fee() }, "should panice")
suite.Require().Panics(func() { tx.Cost() }, "should panice")
suite.Require().Panics(func() { tx.Fee() }, "should panic")
suite.Require().Panics(func() { tx.Cost() }, "should panic")
}
+2 -2
View File
@@ -89,7 +89,7 @@ func (log *Log) ToEthereum() *ethtypes.Log {
}
func NewLogsFromEth(ethlogs []*ethtypes.Log) []*Log {
var logs []*Log // nolint: prealloc
var logs []*Log //nolint: prealloc
for _, ethlog := range ethlogs {
logs = append(logs, NewLogFromEth(ethlog))
}
@@ -99,7 +99,7 @@ func NewLogsFromEth(ethlogs []*ethtypes.Log) []*Log {
// LogsToEthereum casts the Ethermint Logs to a slice of Ethereum Logs.
func LogsToEthereum(logs []*Log) []*ethtypes.Log {
var ethLogs []*ethtypes.Log // nolint: prealloc
var ethLogs []*ethtypes.Log //nolint: prealloc
for i := range logs {
ethLogs = append(ethLogs, logs[i].ToEthereum())
}
+40
View File
@@ -45,6 +45,14 @@ func TestTransactionLogsValidate(t *testing.T) {
},
false,
},
{
"nil log",
TransactionLogs{
Hash: common.BytesToHash([]byte("tx_hash")).String(),
Logs: []*Log{nil},
},
false,
},
{
"invalid log",
TransactionLogs{
@@ -158,3 +166,35 @@ func TestValidateLog(t *testing.T) {
}
}
}
func TestConversionFunctions(t *testing.T) {
addr := tests.GenerateAddress().String()
txLogs := TransactionLogs{
Hash: common.BytesToHash([]byte("tx_hash")).String(),
Logs: []*Log{
{
Address: addr,
Topics: []string{common.BytesToHash([]byte("topic")).String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: common.BytesToHash([]byte("tx_hash")).String(),
TxIndex: 1,
BlockHash: common.BytesToHash([]byte("block_hash")).String(),
Index: 1,
Removed: false,
},
},
}
// convert valid log to eth logs and back (and validate)
conversionLogs := NewTransactionLogsFromEth(common.BytesToHash([]byte("tx_hash")), txLogs.EthLogs())
conversionErr := conversionLogs.Validate()
// create new transaction logs as copy of old valid one (and validate)
copyLogs := NewTransactionLogs(common.BytesToHash([]byte("tx_hash")), txLogs.Logs)
copyErr := copyLogs.Validate()
require.Nil(t, conversionErr)
require.Nil(t, copyErr)
}
+42 -14
View File
@@ -5,12 +5,14 @@ import (
"fmt"
"math/big"
sdkmath "cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
@@ -22,8 +24,9 @@ import (
)
var (
_ sdk.Msg = &MsgEthereumTx{}
_ sdk.Tx = &MsgEthereumTx{}
_ sdk.Msg = &MsgEthereumTx{}
_ sdk.Tx = &MsgEthereumTx{}
_ ante.GasTx = &MsgEthereumTx{}
_ codectypes.UnpackInterfacesMessage = MsgEthereumTx{}
)
@@ -61,7 +64,7 @@ func newMsgEthereumTx(
gasLimit uint64, gasPrice, gasFeeCap, gasTipCap *big.Int, input []byte, accesses *ethtypes.AccessList,
) *MsgEthereumTx {
var (
cid, amt, gp *sdk.Int
cid, amt, gp *sdkmath.Int
toAddr string
txData TxData
)
@@ -71,17 +74,17 @@ func newMsgEthereumTx(
}
if amount != nil {
amountInt := sdk.NewIntFromBigInt(amount)
amountInt := sdkmath.NewIntFromBigInt(amount)
amt = &amountInt
}
if chainID != nil {
chainIDInt := sdk.NewIntFromBigInt(chainID)
chainIDInt := sdkmath.NewIntFromBigInt(chainID)
cid = &chainIDInt
}
if gasPrice != nil {
gasPriceInt := sdk.NewIntFromBigInt(gasPrice)
gasPriceInt := sdkmath.NewIntFromBigInt(gasPrice)
gp = &gasPriceInt
}
@@ -96,8 +99,8 @@ func newMsgEthereumTx(
Data: input,
}
case accesses != nil && gasFeeCap != nil && gasTipCap != nil:
gtc := sdk.NewIntFromBigInt(gasTipCap)
gfc := sdk.NewIntFromBigInt(gasFeeCap)
gtc := sdkmath.NewIntFromBigInt(gasTipCap)
gfc := sdkmath.NewIntFromBigInt(gasFeeCap)
txData = &DynamicFeeTx{
ChainID: cid,
@@ -129,10 +132,12 @@ func newMsgEthereumTx(
panic(err)
}
return &MsgEthereumTx{Data: dataAny}
msg := MsgEthereumTx{Data: dataAny}
msg.Hash = msg.AsTransaction().Hash().Hex()
return &msg
}
// fromEthereumTx populates the message fields from the given ethereum transaction
// FromEthereumTx populates the message fields from the given ethereum transaction
func (msg *MsgEthereumTx) FromEthereumTx(tx *ethtypes.Transaction) error {
txData, err := NewTxDataFromTx(tx)
if err != nil {
@@ -145,7 +150,6 @@ func (msg *MsgEthereumTx) FromEthereumTx(tx *ethtypes.Transaction) error {
}
msg.Data = anyTxData
msg.Size_ = float64(tx.Size())
msg.Hash = tx.Hash().Hex()
return nil
}
@@ -165,12 +169,32 @@ func (msg MsgEthereumTx) ValidateBasic() error {
}
}
// Validate Size_ field, should be kept empty
if msg.Size_ != 0 {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "tx size is deprecated")
}
txData, err := UnpackTxData(msg.Data)
if err != nil {
return sdkerrors.Wrap(err, "failed to unpack tx data")
}
return txData.Validate()
// prevent txs with 0 gas to fill up the mempool
if txData.GetGas() == 0 {
return sdkerrors.Wrap(ErrInvalidGasLimit, "gas limit must not be zero")
}
if err := txData.Validate(); err != nil {
return err
}
// Validate Hash field after validated txData to avoid panic
txHash := msg.AsTransaction().Hash().Hex()
if msg.Hash != txHash {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid tx hash %s, expected: %s", msg.Hash, txHash)
}
return nil
}
// GetMsgs returns a single MsgEthereumTx as an sdk.Msg.
@@ -330,12 +354,16 @@ func (msg *MsgEthereumTx) BuildTx(b client.TxBuilder, evmDenom string) (signing.
return nil, err
}
fees := make(sdk.Coins, 0)
feeAmt := sdk.NewIntFromBigInt(txData.Fee())
feeAmt := sdkmath.NewIntFromBigInt(txData.Fee())
if feeAmt.Sign() > 0 {
fees = append(fees, sdk.NewCoin(evmDenom, feeAmt))
}
builder.SetExtensionOptions(option)
// A valid msg should have empty `From`
msg.From = ""
err = builder.SetMsgs(msg)
if err != nil {
return nil, err
+493 -81
View File
@@ -4,8 +4,10 @@ import (
"fmt"
"math/big"
"reflect"
"strings"
"testing"
sdkmath "cosmossdk.io/math"
"github.com/stretchr/testify/suite"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
@@ -28,10 +30,11 @@ const invalidFromAddress = "0x0000"
type MsgsTestSuite struct {
suite.Suite
signer keyring.Signer
from common.Address
to common.Address
chainID *big.Int
signer keyring.Signer
from common.Address
to common.Address
chainID *big.Int
hundredBigInt *big.Int
clientCtx client.Context
}
@@ -47,6 +50,7 @@ func (suite *MsgsTestSuite) SetupTest() {
suite.from = from
suite.to = tests.GenerateAddress()
suite.chainID = big.NewInt(1)
suite.hundredBigInt = big.NewInt(100)
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig)
@@ -70,80 +74,384 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_Constructor() {
}
func (suite *MsgsTestSuite) TestMsgEthereumTx_BuildTx() {
msg := types.NewTx(nil, 0, &suite.to, nil, 100000, big.NewInt(1), big.NewInt(1), big.NewInt(0), []byte("test"), nil)
testCases := []struct {
name string
msg *types.MsgEthereumTx
expError bool
}{
{
"build tx - pass",
types.NewTx(nil, 0, &suite.to, nil, 100000, big.NewInt(1), big.NewInt(1), big.NewInt(0), []byte("test"), nil),
false,
},
{
"build tx - fail: nil data",
types.NewTx(nil, 0, &suite.to, nil, 100000, big.NewInt(1), big.NewInt(1), big.NewInt(0), []byte("test"), nil),
true,
},
}
err := msg.ValidateBasic()
suite.Require().NoError(err)
for _, tc := range testCases {
if strings.Contains(tc.name, "nil data") {
tc.msg.Data = nil
}
tx, err := msg.BuildTx(suite.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
suite.Require().NoError(err)
tx, err := tc.msg.BuildTx(suite.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
if tc.expError {
suite.Require().Error(err)
} else {
suite.Require().NoError(err)
suite.Require().Empty(tx.GetMemo())
suite.Require().Empty(tx.GetTimeoutHeight())
suite.Require().Equal(uint64(100000), tx.GetGas())
suite.Require().Equal(sdk.NewCoins(sdk.NewCoin("aphoton", sdk.NewInt(100000))), tx.GetFee())
suite.Require().Empty(tx.GetMemo())
suite.Require().Empty(tx.GetTimeoutHeight())
suite.Require().Equal(uint64(100000), tx.GetGas())
suite.Require().Equal(sdk.NewCoins(sdk.NewCoin("aphoton", sdkmath.NewInt(100000))), tx.GetFee())
}
}
}
func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() {
hundredInt := sdk.NewInt(100)
zeroInt := sdk.ZeroInt()
minusOneInt := sdk.NewInt(-1)
exp_2_255 := sdk.NewIntFromBigInt(new(big.Int).Exp(big.NewInt(2), big.NewInt(255), nil))
hundredInt := big.NewInt(100)
zeroInt := big.NewInt(0)
minusOneInt := big.NewInt(-1)
exp_2_255 := new(big.Int).Exp(big.NewInt(2), big.NewInt(255), nil)
testCases := []struct {
msg string
to string
amount *sdk.Int
gasPrice *sdk.Int
amount *big.Int
gasLimit uint64
gasPrice *big.Int
gasFeeCap *big.Int
gasTipCap *big.Int
from string
accessList *ethtypes.AccessList
chainID *sdk.Int
chainID *big.Int
expectPass bool
}{
{msg: "pass with recipient - Legacy Tx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &hundredInt, expectPass: true},
{msg: "pass with recipient - AccessList Tx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &zeroInt, accessList: &ethtypes.AccessList{}, chainID: &hundredInt, expectPass: true},
{msg: "pass contract - Legacy Tx", to: "", amount: &hundredInt, gasPrice: &hundredInt, expectPass: true},
// {msg: "invalid recipient", to: invalidFromAddress, amount: &minusOneInt, gasPrice: &hundredInt, expectPass: false},
{msg: "nil amount - Legacy Tx", to: suite.to.Hex(), amount: nil, gasPrice: &hundredInt, expectPass: true},
{msg: "negative amount - Legacy Tx", to: suite.to.Hex(), amount: &minusOneInt, gasPrice: &hundredInt, expectPass: false},
{msg: "nil gas price - Legacy Tx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: nil, expectPass: false},
{msg: "negative gas price - Legacy Tx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &minusOneInt, expectPass: false},
{msg: "zero gas price - Legacy Tx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &zeroInt, expectPass: true},
{msg: "invalid from address - Legacy Tx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &zeroInt, from: invalidFromAddress, expectPass: false},
{msg: "out of bound gas fee - Legacy Tx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &exp_2_255, expectPass: false},
{msg: "nil amount - AccessListTx", to: suite.to.Hex(), amount: nil, gasPrice: &hundredInt, accessList: &ethtypes.AccessList{}, chainID: &hundredInt, expectPass: true},
{msg: "negative amount - AccessListTx", to: suite.to.Hex(), amount: &minusOneInt, gasPrice: &hundredInt, accessList: &ethtypes.AccessList{}, chainID: nil, expectPass: false},
{msg: "nil gas price - AccessListTx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: nil, accessList: &ethtypes.AccessList{}, chainID: &hundredInt, expectPass: false},
{msg: "negative gas price - AccessListTx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &minusOneInt, accessList: &ethtypes.AccessList{}, chainID: nil, expectPass: false},
{msg: "zero gas price - AccessListTx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &zeroInt, accessList: &ethtypes.AccessList{}, chainID: &hundredInt, expectPass: true},
{msg: "invalid from address - AccessListTx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &zeroInt, from: invalidFromAddress, accessList: &ethtypes.AccessList{}, chainID: &hundredInt, expectPass: false},
{msg: "chain ID not set on AccessListTx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &zeroInt, accessList: &ethtypes.AccessList{}, chainID: nil, expectPass: false},
{
msg: "pass with recipient - Legacy Tx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: hundredInt,
gasFeeCap: nil,
gasTipCap: nil,
expectPass: true,
},
{
msg: "pass with recipient - AccessList Tx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: zeroInt,
gasFeeCap: nil,
gasTipCap: nil,
accessList: &ethtypes.AccessList{},
chainID: hundredInt,
expectPass: true,
},
{
msg: "pass with recipient - DynamicFee Tx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: zeroInt,
gasFeeCap: hundredInt,
gasTipCap: zeroInt,
accessList: &ethtypes.AccessList{},
chainID: hundredInt,
expectPass: true,
},
{
msg: "pass contract - Legacy Tx",
to: "",
amount: hundredInt,
gasLimit: 1000,
gasPrice: hundredInt,
gasFeeCap: nil,
gasTipCap: nil,
expectPass: true,
},
{
msg: "invalid recipient",
to: invalidFromAddress,
amount: minusOneInt,
gasLimit: 1000,
gasPrice: hundredInt,
expectPass: false,
},
{
msg: "nil amount - Legacy Tx",
to: suite.to.Hex(),
amount: nil,
gasLimit: 1000,
gasPrice: hundredInt,
gasFeeCap: nil,
gasTipCap: nil,
expectPass: true,
},
{
msg: "negative amount - Legacy Tx",
to: suite.to.Hex(),
amount: minusOneInt,
gasLimit: 1000,
gasPrice: hundredInt,
gasFeeCap: nil,
gasTipCap: nil,
expectPass: false,
},
{
msg: "zero gas limit - Legacy Tx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 0,
gasPrice: hundredInt,
gasFeeCap: nil,
gasTipCap: nil,
expectPass: false,
},
{
msg: "nil gas price - Legacy Tx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: nil,
gasFeeCap: nil,
gasTipCap: nil,
expectPass: false,
},
{
msg: "negative gas price - Legacy Tx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: minusOneInt,
gasFeeCap: nil,
gasTipCap: nil,
expectPass: false,
},
{
msg: "zero gas price - Legacy Tx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: zeroInt,
gasFeeCap: nil,
gasTipCap: nil,
expectPass: true,
},
{
msg: "invalid from address - Legacy Tx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: zeroInt,
gasFeeCap: nil,
gasTipCap: nil,
from: invalidFromAddress,
expectPass: false,
},
{
msg: "out of bound gas fee - Legacy Tx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: exp_2_255,
gasFeeCap: nil,
gasTipCap: nil,
expectPass: false,
},
{
msg: "nil amount - AccessListTx",
to: suite.to.Hex(),
amount: nil,
gasLimit: 1000,
gasPrice: hundredInt,
gasFeeCap: nil,
gasTipCap: nil,
accessList: &ethtypes.AccessList{},
chainID: hundredInt,
expectPass: true,
},
{
msg: "negative amount - AccessListTx",
to: suite.to.Hex(),
amount: minusOneInt,
gasLimit: 1000,
gasPrice: hundredInt,
gasFeeCap: nil,
gasTipCap: nil,
accessList: &ethtypes.AccessList{},
chainID: nil,
expectPass: false,
},
{
msg: "zero gas limit - AccessListTx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 0,
gasPrice: zeroInt,
gasFeeCap: nil,
gasTipCap: nil,
accessList: &ethtypes.AccessList{},
chainID: hundredInt,
expectPass: false,
},
{
msg: "nil gas price - AccessListTx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: nil,
gasFeeCap: nil,
gasTipCap: nil,
accessList: &ethtypes.AccessList{},
chainID: hundredInt,
expectPass: false,
},
{
msg: "negative gas price - AccessListTx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: minusOneInt,
gasFeeCap: nil,
gasTipCap: nil,
accessList: &ethtypes.AccessList{},
chainID: nil,
expectPass: false,
},
{
msg: "zero gas price - AccessListTx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: zeroInt,
gasFeeCap: nil,
gasTipCap: nil,
accessList: &ethtypes.AccessList{},
chainID: hundredInt,
expectPass: true,
},
{
msg: "invalid from address - AccessListTx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: zeroInt,
gasFeeCap: nil,
gasTipCap: nil,
from: invalidFromAddress,
accessList: &ethtypes.AccessList{},
chainID: hundredInt,
expectPass: false,
},
{
msg: "chain ID not set on AccessListTx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: zeroInt,
gasFeeCap: nil,
gasTipCap: nil,
accessList: &ethtypes.AccessList{},
chainID: nil,
expectPass: false,
},
{
msg: "nil tx.Data - AccessList Tx",
to: suite.to.Hex(),
amount: hundredInt,
gasLimit: 1000,
gasPrice: zeroInt,
gasFeeCap: nil,
gasTipCap: nil,
accessList: &ethtypes.AccessList{},
chainID: hundredInt,
expectPass: false,
},
}
for i, tc := range testCases {
to := common.HexToAddress(tc.from)
for _, tc := range testCases {
suite.Run(tc.msg, func() {
to := common.HexToAddress(tc.from)
var chainID, amount, gasPrice *big.Int
if tc.chainID != nil {
chainID = tc.chainID.BigInt()
}
if tc.amount != nil {
amount = tc.amount.BigInt()
}
if tc.gasPrice != nil {
gasPrice = tc.gasPrice.BigInt()
}
tx := types.NewTx(tc.chainID, 1, &to, tc.amount, tc.gasLimit, tc.gasPrice, tc.gasFeeCap, tc.gasTipCap, nil, tc.accessList)
tx.From = tc.from
tx := types.NewTx(chainID, 1, &to, amount, 1000, gasPrice, nil, nil, nil, tc.accessList)
tx.From = tc.from
// apply nil assignment here to test ValidateBasic function instead of NewTx
if strings.Contains(tc.msg, "nil tx.Data") {
tx.Data = nil
}
err := tx.ValidateBasic()
err := tx.ValidateBasic()
if tc.expectPass {
suite.Require().NoError(err, "valid test %d failed: %s, %v", i, tc.msg)
} else {
suite.Require().Error(err, "invalid test %d passed: %s, %v", i, tc.msg)
}
if tc.expectPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasicAdvanced() {
hundredInt := big.NewInt(100)
testCases := []struct {
msg string
msgBuilder func() *types.MsgEthereumTx
expectPass bool
}{
{
"fails - invalid tx hash",
func() *types.MsgEthereumTx {
msg := types.NewTxContract(
hundredInt,
1,
big.NewInt(10),
100000,
big.NewInt(150),
big.NewInt(200),
nil,
nil,
nil,
)
msg.Hash = "0x00"
return msg
},
false,
},
{
"fails - invalid size",
func() *types.MsgEthereumTx {
msg := types.NewTxContract(
hundredInt,
1,
big.NewInt(10),
100000,
big.NewInt(150),
big.NewInt(200),
nil,
nil,
nil,
)
msg.Size_ = 1
return msg
},
false,
},
}
for _, tc := range testCases {
suite.Run(tc.msg, func() {
err := tc.msgBuilder().ValidateBasic()
if tc.expectPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}
@@ -215,6 +523,69 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_Sign() {
}
}
func (suite *MsgsTestSuite) TestMsgEthereumTx_Getters() {
testCases := []struct {
name string
tx *types.MsgEthereumTx
ethSigner ethtypes.Signer
exp *big.Int
}{
{
"get fee - pass",
types.NewTx(suite.chainID, 0, &suite.to, nil, 50, suite.hundredBigInt, nil, nil, nil, &ethtypes.AccessList{}),
ethtypes.NewEIP2930Signer(suite.chainID),
big.NewInt(5000),
},
{
"get fee - fail: nil data",
types.NewTx(suite.chainID, 0, &suite.to, nil, 50, suite.hundredBigInt, nil, nil, nil, &ethtypes.AccessList{}),
ethtypes.NewEIP2930Signer(suite.chainID),
nil,
},
{
"get effective fee - pass",
types.NewTx(suite.chainID, 0, &suite.to, nil, 50, suite.hundredBigInt, nil, nil, nil, &ethtypes.AccessList{}),
ethtypes.NewEIP2930Signer(suite.chainID),
big.NewInt(5000),
},
{
"get effective fee - fail: nil data",
types.NewTx(suite.chainID, 0, &suite.to, nil, 50, suite.hundredBigInt, nil, nil, nil, &ethtypes.AccessList{}),
ethtypes.NewEIP2930Signer(suite.chainID),
nil,
},
{
"get gas - pass",
types.NewTx(suite.chainID, 0, &suite.to, nil, 50, suite.hundredBigInt, nil, nil, nil, &ethtypes.AccessList{}),
ethtypes.NewEIP2930Signer(suite.chainID),
big.NewInt(50),
},
{
"get gas - fail: nil data",
types.NewTx(suite.chainID, 0, &suite.to, nil, 50, suite.hundredBigInt, nil, nil, nil, &ethtypes.AccessList{}),
ethtypes.NewEIP2930Signer(suite.chainID),
big.NewInt(0),
},
}
var fee, effFee *big.Int
for _, tc := range testCases {
if strings.Contains(tc.name, "nil data") {
tc.tx.Data = nil
}
if strings.Contains(tc.name, "get fee") {
fee = tc.tx.GetFee()
suite.Require().Equal(tc.exp, fee)
} else if strings.Contains(tc.name, "get effective fee") {
effFee = tc.tx.GetEffectiveFee(big.NewInt(0))
suite.Require().Equal(tc.exp, effFee)
} else if strings.Contains(tc.name, "get gas") {
gas := tc.tx.GetGas()
suite.Require().Equal(tc.exp.Uint64(), gas)
}
}
}
func (suite *MsgsTestSuite) TestFromEthereumTx() {
privkey, _ := ethsecp256k1.GenerateKey()
ethPriv, err := privkey.ToECDSA()
@@ -229,37 +600,78 @@ func (suite *MsgsTestSuite) TestFromEthereumTx() {
buildTx func() *ethtypes.Transaction
}{
{"success, normal tx", true, func() *ethtypes.Transaction {
tx := ethtypes.NewTransaction(
0,
common.BigToAddress(big.NewInt(1)),
big.NewInt(10),
21000, big.NewInt(0),
nil,
)
tx := ethtypes.NewTx(&ethtypes.AccessListTx{
Nonce: 0,
Data: nil,
To: &suite.to,
Value: big.NewInt(10),
GasPrice: big.NewInt(1),
Gas: 21000,
})
tx, err := ethtypes.SignTx(tx, ethtypes.NewEIP2930Signer(suite.chainID), ethPriv)
suite.Require().NoError(err)
return tx
}},
{"fail, value bigger than 256bits", false, func() *ethtypes.Transaction {
tx := ethtypes.NewTransaction(
0,
common.BigToAddress(big.NewInt(1)),
exp_10_80,
21000, big.NewInt(0),
nil,
)
{"success, DynamicFeeTx", true, func() *ethtypes.Transaction {
tx := ethtypes.NewTx(&ethtypes.DynamicFeeTx{
Nonce: 0,
Data: nil,
To: &suite.to,
Value: big.NewInt(10),
Gas: 21000,
})
tx, err := ethtypes.SignTx(tx, ethtypes.NewLondonSigner(suite.chainID), ethPriv)
suite.Require().NoError(err)
return tx
}},
{"fail, value bigger than 256bits - AccessListTx", false, func() *ethtypes.Transaction {
tx := ethtypes.NewTx(&ethtypes.AccessListTx{
Nonce: 0,
Data: nil,
To: &suite.to,
Value: exp_10_80,
GasPrice: big.NewInt(1),
Gas: 21000,
})
tx, err := ethtypes.SignTx(tx, ethtypes.NewEIP2930Signer(suite.chainID), ethPriv)
suite.Require().NoError(err)
return tx
}},
{"fail, gas price bigger than 256bits", false, func() *ethtypes.Transaction {
tx := ethtypes.NewTransaction(
0,
common.BigToAddress(big.NewInt(1)),
big.NewInt(10),
21000, exp_10_80,
nil,
)
{"fail, gas price bigger than 256bits - AccessListTx", false, func() *ethtypes.Transaction {
tx := ethtypes.NewTx(&ethtypes.AccessListTx{
Nonce: 0,
Data: nil,
To: &suite.to,
Value: big.NewInt(1),
GasPrice: exp_10_80,
Gas: 21000,
})
tx, err := ethtypes.SignTx(tx, ethtypes.NewEIP2930Signer(suite.chainID), ethPriv)
suite.Require().NoError(err)
return tx
}},
{"fail, value bigger than 256bits - LegacyTx", false, func() *ethtypes.Transaction {
tx := ethtypes.NewTx(&ethtypes.LegacyTx{
Nonce: 0,
Data: nil,
To: &suite.to,
Value: exp_10_80,
GasPrice: big.NewInt(1),
Gas: 21000,
})
tx, err := ethtypes.SignTx(tx, ethtypes.NewEIP2930Signer(suite.chainID), ethPriv)
suite.Require().NoError(err)
return tx
}},
{"fail, gas price bigger than 256bits - LegacyTx", false, func() *ethtypes.Transaction {
tx := ethtypes.NewTx(&ethtypes.LegacyTx{
Nonce: 0,
Data: nil,
To: &suite.to,
Value: big.NewInt(1),
GasPrice: exp_10_80,
Gas: 21000,
})
tx, err := ethtypes.SignTx(tx, ethtypes.NewEIP2930Signer(suite.chainID), ethPriv)
suite.Require().NoError(err)
return tx
+19 -11
View File
@@ -14,17 +14,23 @@ import (
var _ paramtypes.ParamSet = &Params{}
const (
var (
// DefaultEVMDenom defines the default EVM denomination on Ethermint
DefaultEVMDenom = types.AttoPhoton
// DefaultMinGasMultiplier is 0.5 or 50%
DefaultMinGasMultiplier = sdk.NewDecWithPrec(50, 2)
// DefaultAllowUnprotectedTxs rejects all unprotected txs (i.e false)
DefaultAllowUnprotectedTxs = false
)
// Parameter keys
var (
ParamStoreKeyEVMDenom = []byte("EVMDenom")
ParamStoreKeyEnableCreate = []byte("EnableCreate")
ParamStoreKeyEnableCall = []byte("EnableCall")
ParamStoreKeyExtraEIPs = []byte("EnableExtraEIPs")
ParamStoreKeyChainConfig = []byte("ChainConfig")
ParamStoreKeyEVMDenom = []byte("EVMDenom")
ParamStoreKeyEnableCreate = []byte("EnableCreate")
ParamStoreKeyEnableCall = []byte("EnableCall")
ParamStoreKeyExtraEIPs = []byte("EnableExtraEIPs")
ParamStoreKeyChainConfig = []byte("ChainConfig")
ParamStoreKeyAllowUnprotectedTxs = []byte("AllowUnprotectedTxs")
// AvailableExtraEIPs define the list of all EIPs that can be enabled by the
// EVM interpreter. These EIPs are applied in order and can override the
@@ -54,11 +60,12 @@ func NewParams(evmDenom string, enableCreate, enableCall bool, config ChainConfi
// ExtraEIPs is empty to prevent overriding the latest hard fork instruction set
func DefaultParams() Params {
return Params{
EvmDenom: DefaultEVMDenom,
EnableCreate: true,
EnableCall: true,
ChainConfig: DefaultChainConfig(),
ExtraEIPs: nil,
EvmDenom: DefaultEVMDenom,
EnableCreate: true,
EnableCall: true,
ChainConfig: DefaultChainConfig(),
ExtraEIPs: nil,
AllowUnprotectedTxs: DefaultAllowUnprotectedTxs,
}
}
@@ -70,6 +77,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
paramtypes.NewParamSetPair(ParamStoreKeyEnableCall, &p.EnableCall, validateBool),
paramtypes.NewParamSetPair(ParamStoreKeyExtraEIPs, &p.ExtraEIPs, validateEIPs),
paramtypes.NewParamSetPair(ParamStoreKeyChainConfig, &p.ChainConfig, validateChainConfig),
paramtypes.NewParamSetPair(ParamStoreKeyAllowUnprotectedTxs, &p.AllowUnprotectedTxs, validateBool),
}
}
-5
View File
@@ -45,11 +45,6 @@ func TestParamsValidate(t *testing.T) {
},
true,
},
{
"invalid chain config",
NewParams("ara", true, true, ChainConfig{}, 2929, 1884, 1344),
false,
},
}
for _, tc := range testCases {
+422 -119
View File
@@ -6,6 +6,7 @@ package types
import (
context "context"
fmt "fmt"
github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types"
query "github.com/cosmos/cosmos-sdk/types/query"
_ "github.com/gogo/protobuf/gogoproto"
grpc1 "github.com/gogo/protobuf/grpc"
@@ -890,8 +891,6 @@ func (m *EstimateGasResponse) GetGas() uint64 {
type QueryTraceTxRequest struct {
// msgEthereumTx for the requested transaction
Msg *MsgEthereumTx `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"`
// transaction index
TxIndex uint64 `protobuf:"varint,2,opt,name=tx_index,json=txIndex,proto3" json:"tx_index,omitempty"`
// TraceConfig holds extra parameters to trace functions.
TraceConfig *TraceConfig `protobuf:"bytes,3,opt,name=trace_config,json=traceConfig,proto3" json:"trace_config,omitempty"`
// the predecessor transactions included in the same block
@@ -945,13 +944,6 @@ func (m *QueryTraceTxRequest) GetMsg() *MsgEthereumTx {
return nil
}
func (m *QueryTraceTxRequest) GetTxIndex() uint64 {
if m != nil {
return m.TxIndex
}
return 0
}
func (m *QueryTraceTxRequest) GetTraceConfig() *TraceConfig {
if m != nil {
return m.TraceConfig
@@ -1160,6 +1152,82 @@ func (m *QueryTraceBlockResponse) GetData() []byte {
return nil
}
// QueryBaseFeeRequest defines the request type for querying the EIP1559 base
// fee.
type QueryBaseFeeRequest struct {
}
func (m *QueryBaseFeeRequest) Reset() { *m = QueryBaseFeeRequest{} }
func (m *QueryBaseFeeRequest) String() string { return proto.CompactTextString(m) }
func (*QueryBaseFeeRequest) ProtoMessage() {}
func (*QueryBaseFeeRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_e15a877459347994, []int{22}
}
func (m *QueryBaseFeeRequest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *QueryBaseFeeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_QueryBaseFeeRequest.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *QueryBaseFeeRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_QueryBaseFeeRequest.Merge(m, src)
}
func (m *QueryBaseFeeRequest) XXX_Size() int {
return m.Size()
}
func (m *QueryBaseFeeRequest) XXX_DiscardUnknown() {
xxx_messageInfo_QueryBaseFeeRequest.DiscardUnknown(m)
}
var xxx_messageInfo_QueryBaseFeeRequest proto.InternalMessageInfo
// BaseFeeResponse returns the EIP1559 base fee.
type QueryBaseFeeResponse struct {
BaseFee *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=base_fee,json=baseFee,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"base_fee,omitempty"`
}
func (m *QueryBaseFeeResponse) Reset() { *m = QueryBaseFeeResponse{} }
func (m *QueryBaseFeeResponse) String() string { return proto.CompactTextString(m) }
func (*QueryBaseFeeResponse) ProtoMessage() {}
func (*QueryBaseFeeResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_e15a877459347994, []int{23}
}
func (m *QueryBaseFeeResponse) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *QueryBaseFeeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_QueryBaseFeeResponse.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *QueryBaseFeeResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_QueryBaseFeeResponse.Merge(m, src)
}
func (m *QueryBaseFeeResponse) XXX_Size() int {
return m.Size()
}
func (m *QueryBaseFeeResponse) XXX_DiscardUnknown() {
xxx_messageInfo_QueryBaseFeeResponse.DiscardUnknown(m)
}
var xxx_messageInfo_QueryBaseFeeResponse proto.InternalMessageInfo
func init() {
proto.RegisterType((*QueryAccountRequest)(nil), "ethermint.evm.v1.QueryAccountRequest")
proto.RegisterType((*QueryAccountResponse)(nil), "ethermint.evm.v1.QueryAccountResponse")
@@ -1183,94 +1251,100 @@ func init() {
proto.RegisterType((*QueryTraceTxResponse)(nil), "ethermint.evm.v1.QueryTraceTxResponse")
proto.RegisterType((*QueryTraceBlockRequest)(nil), "ethermint.evm.v1.QueryTraceBlockRequest")
proto.RegisterType((*QueryTraceBlockResponse)(nil), "ethermint.evm.v1.QueryTraceBlockResponse")
proto.RegisterType((*QueryBaseFeeRequest)(nil), "ethermint.evm.v1.QueryBaseFeeRequest")
proto.RegisterType((*QueryBaseFeeResponse)(nil), "ethermint.evm.v1.QueryBaseFeeResponse")
}
func init() { proto.RegisterFile("ethermint/evm/v1/query.proto", fileDescriptor_e15a877459347994) }
var fileDescriptor_e15a877459347994 = []byte{
// 1299 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0x4d, 0x6f, 0x1b, 0x45,
0x18, 0xce, 0x26, 0x4e, 0x9c, 0xbe, 0x4e, 0x4b, 0x98, 0x06, 0xea, 0x2e, 0x89, 0x9d, 0x6e, 0x9b,
0xaf, 0x36, 0xdd, 0x25, 0x06, 0x55, 0xa2, 0x12, 0x82, 0x24, 0x2a, 0x05, 0xb5, 0x45, 0xc5, 0x44,
0x1c, 0xb8, 0x58, 0xe3, 0xf5, 0x74, 0xbd, 0xaa, 0x77, 0xc7, 0xdd, 0x19, 0x9b, 0x4d, 0x4b, 0x39,
0x20, 0x51, 0x15, 0xf5, 0x52, 0x09, 0xce, 0xa8, 0xff, 0x80, 0xbf, 0xd1, 0x63, 0x25, 0x2e, 0x9c,
0x00, 0xb5, 0x1c, 0xb8, 0xf6, 0x1f, 0xa0, 0xf9, 0xd8, 0xf8, 0x63, 0xbd, 0x71, 0x8a, 0x7a, 0xe0,
0x36, 0x1f, 0xef, 0xbc, 0xcf, 0xf3, 0x7e, 0xcc, 0x3c, 0x03, 0x8b, 0x84, 0x37, 0x49, 0x14, 0xf8,
0x21, 0x77, 0x48, 0x37, 0x70, 0xba, 0x5b, 0xce, 0x9d, 0x0e, 0x89, 0xf6, 0xed, 0x76, 0x44, 0x39,
0x45, 0xf3, 0x07, 0xbb, 0x36, 0xe9, 0x06, 0x76, 0x77, 0xcb, 0x5c, 0xf0, 0xa8, 0x47, 0xe5, 0xa6,
0x23, 0x46, 0xca, 0xce, 0x3c, 0xef, 0x52, 0x16, 0x50, 0xe6, 0xd4, 0x31, 0x23, 0xca, 0x81, 0xd3,
0xdd, 0xaa, 0x13, 0x8e, 0xb7, 0x9c, 0x36, 0xf6, 0xfc, 0x10, 0x73, 0x9f, 0x86, 0xda, 0x76, 0xd1,
0xa3, 0xd4, 0x6b, 0x11, 0x07, 0xb7, 0x7d, 0x07, 0x87, 0x21, 0xe5, 0x72, 0x93, 0xe9, 0x5d, 0x33,
0xc5, 0x47, 0x00, 0xab, 0xbd, 0xd3, 0xa9, 0x3d, 0x1e, 0xeb, 0xad, 0xb2, 0x76, 0x2a, 0x67, 0xf5,
0xce, 0x2d, 0x87, 0xfb, 0x01, 0x61, 0x1c, 0x07, 0x6d, 0x65, 0x60, 0x7d, 0x00, 0x27, 0xbf, 0x10,
0xbc, 0xb6, 0x5d, 0x97, 0x76, 0x42, 0x5e, 0x25, 0x77, 0x3a, 0x84, 0x71, 0x54, 0x84, 0x3c, 0x6e,
0x34, 0x22, 0xc2, 0x58, 0xd1, 0x58, 0x36, 0xd6, 0x8f, 0x55, 0x93, 0xe9, 0xe5, 0xd9, 0x87, 0x4f,
0xca, 0x13, 0xff, 0x3c, 0x29, 0x4f, 0x58, 0x2e, 0x2c, 0x0c, 0x1e, 0x65, 0x6d, 0x1a, 0x32, 0x22,
0xce, 0xd6, 0x71, 0x0b, 0x87, 0x2e, 0x49, 0xce, 0xea, 0x29, 0x7a, 0x07, 0x8e, 0xb9, 0xb4, 0x41,
0x6a, 0x4d, 0xcc, 0x9a, 0xc5, 0x49, 0xb9, 0x37, 0x2b, 0x16, 0x3e, 0xc5, 0xac, 0x89, 0x16, 0x60,
0x3a, 0xa4, 0xe2, 0xd0, 0xd4, 0xb2, 0xb1, 0x9e, 0xab, 0xaa, 0x89, 0xf5, 0x11, 0x9c, 0x96, 0x20,
0xbb, 0x32, 0x91, 0xff, 0x81, 0xe5, 0x03, 0x03, 0xcc, 0x51, 0x1e, 0x34, 0xd9, 0x15, 0x38, 0xa1,
0x6a, 0x54, 0x1b, 0xf4, 0x74, 0x5c, 0xad, 0x6e, 0xab, 0x45, 0x64, 0xc2, 0x2c, 0x13, 0xa0, 0x82,
0xdf, 0xa4, 0xe4, 0x77, 0x30, 0x17, 0x2e, 0xb0, 0xf2, 0x5a, 0x0b, 0x3b, 0x41, 0x9d, 0x44, 0x3a,
0x82, 0xe3, 0x7a, 0xf5, 0x73, 0xb9, 0x68, 0x5d, 0x83, 0x45, 0xc9, 0xe3, 0x2b, 0xdc, 0xf2, 0x1b,
0x98, 0xd3, 0x68, 0x28, 0x98, 0x33, 0x30, 0xe7, 0xd2, 0x70, 0x98, 0x47, 0x41, 0xac, 0x6d, 0xa7,
0xa2, 0x7a, 0x64, 0xc0, 0x52, 0x86, 0x37, 0x1d, 0xd8, 0x1a, 0xbc, 0x91, 0xb0, 0x1a, 0xf4, 0x98,
0x90, 0x7d, 0x8d, 0xa1, 0x25, 0x4d, 0xb4, 0xa3, 0xea, 0xfc, 0x2a, 0xe5, 0x79, 0x57, 0x37, 0xd1,
0xc1, 0xd1, 0x71, 0x4d, 0x64, 0x5d, 0xd3, 0x60, 0x5f, 0x72, 0x1a, 0x61, 0x6f, 0x3c, 0x18, 0x9a,
0x87, 0xa9, 0xdb, 0x64, 0x5f, 0xf7, 0x9b, 0x18, 0xf6, 0xc1, 0x6f, 0x6a, 0xf8, 0x03, 0x67, 0x1a,
0x7e, 0x01, 0xa6, 0xbb, 0xb8, 0xd5, 0x49, 0xc0, 0xd5, 0xc4, 0xba, 0x04, 0xf3, 0xba, 0x95, 0x1a,
0xaf, 0x14, 0xe4, 0x1a, 0xbc, 0xd9, 0x77, 0x4e, 0x43, 0x20, 0xc8, 0x89, 0xde, 0x97, 0xa7, 0xe6,
0xaa, 0x72, 0x6c, 0xdd, 0x05, 0x24, 0x0d, 0xf7, 0xe2, 0xeb, 0xd4, 0x63, 0x09, 0x04, 0x82, 0x9c,
0xbc, 0x31, 0xca, 0xbf, 0x1c, 0xa3, 0x4f, 0x00, 0x7a, 0x2f, 0x88, 0x8c, 0xad, 0x50, 0x59, 0xb5,
0x55, 0xd3, 0xda, 0xe2, 0xb9, 0xb1, 0xd5, 0x7b, 0xa5, 0x9f, 0x1b, 0xfb, 0x66, 0x2f, 0x55, 0xd5,
0xbe, 0x93, 0x7d, 0x24, 0x7f, 0x34, 0x74, 0x62, 0x13, 0x70, 0xcd, 0x73, 0x03, 0x72, 0x2d, 0xea,
0x89, 0xe8, 0xa6, 0xd6, 0x0b, 0x95, 0xb7, 0xec, 0xe1, 0xa7, 0xcf, 0xbe, 0x4e, 0xbd, 0xaa, 0x34,
0x41, 0x57, 0x47, 0x90, 0x5a, 0x1b, 0x4b, 0x4a, 0xe1, 0xf4, 0xb3, 0xb2, 0x16, 0x74, 0x1e, 0x6e,
0xe2, 0x08, 0x07, 0x49, 0x1e, 0xac, 0x1b, 0x9a, 0x60, 0xb2, 0xaa, 0x09, 0x5e, 0x82, 0x99, 0xb6,
0x5c, 0x91, 0x09, 0x2a, 0x54, 0x8a, 0x69, 0x8a, 0xea, 0xc4, 0x4e, 0xee, 0xe9, 0x1f, 0xe5, 0x89,
0xaa, 0xb6, 0xb6, 0x3e, 0x84, 0x13, 0x57, 0x78, 0x73, 0x17, 0xb7, 0x5a, 0x7d, 0x89, 0xc6, 0x91,
0xc7, 0x92, 0x92, 0x88, 0x31, 0x3a, 0x05, 0x79, 0x0f, 0xb3, 0x9a, 0x8b, 0xdb, 0xfa, 0x76, 0xcc,
0x78, 0x98, 0xed, 0xe2, 0xb6, 0xb5, 0x06, 0x27, 0xaf, 0x30, 0xee, 0x07, 0x98, 0x93, 0xab, 0xb8,
0xc7, 0x66, 0x1e, 0xa6, 0x3c, 0xac, 0x5c, 0xe4, 0xaa, 0x62, 0x68, 0xbd, 0x9c, 0x4c, 0x12, 0x1b,
0x61, 0x97, 0xec, 0xc5, 0x09, 0xda, 0x16, 0x4c, 0x05, 0xcc, 0xd3, 0xa4, 0xcb, 0x69, 0xd2, 0x37,
0x98, 0x77, 0x45, 0xac, 0x91, 0x4e, 0xb0, 0x17, 0x57, 0x85, 0x2d, 0x3a, 0x0d, 0xb3, 0x3c, 0xae,
0xf9, 0x61, 0x83, 0xc4, 0x9a, 0x4d, 0x9e, 0xc7, 0x9f, 0x89, 0x29, 0xfa, 0x18, 0xe6, 0xb8, 0xf0,
0x5f, 0x73, 0x69, 0x78, 0xcb, 0xf7, 0xe4, 0x45, 0x2d, 0x54, 0x96, 0xd2, 0x6e, 0x25, 0x8b, 0x5d,
0x69, 0x54, 0x2d, 0xf0, 0xde, 0x04, 0xed, 0xc2, 0x5c, 0x3b, 0x22, 0x0d, 0xe2, 0x12, 0xc6, 0x68,
0xc4, 0x8a, 0x39, 0x59, 0xf0, 0xb1, 0xc4, 0x06, 0x0e, 0x89, 0x57, 0xac, 0xde, 0xa2, 0xee, 0xed,
0xe4, 0xbd, 0x98, 0x5e, 0x36, 0xd6, 0xa7, 0xaa, 0x05, 0xb9, 0xa6, 0x5e, 0x0b, 0xb4, 0x04, 0xa0,
0x4c, 0x64, 0x53, 0xcf, 0xc8, 0xa6, 0x3e, 0x26, 0x57, 0xa4, 0x0e, 0xec, 0x26, 0xdb, 0x42, 0xaa,
0x8a, 0x79, 0x19, 0x86, 0x69, 0x2b, 0x1d, 0xb3, 0x13, 0x1d, 0xb3, 0xf7, 0x12, 0x1d, 0xdb, 0x99,
0x15, 0x45, 0x7d, 0xfc, 0x67, 0xd9, 0xd0, 0x4e, 0xc4, 0x8e, 0x75, 0x5e, 0xdf, 0xeb, 0x83, 0x94,
0xf7, 0x2e, 0x5d, 0x03, 0x73, 0x9c, 0x54, 0x58, 0x8c, 0xad, 0x9f, 0x27, 0xe1, 0xed, 0x9e, 0xf1,
0x8e, 0xf0, 0xd1, 0x57, 0x22, 0x1e, 0x27, 0xad, 0x3f, 0xbe, 0x44, 0x3c, 0x66, 0xaf, 0xa1, 0x0e,
0xff, 0x93, 0x14, 0x5e, 0x84, 0x53, 0xa9, 0xac, 0x64, 0x67, 0xb1, 0xf2, 0xb2, 0x00, 0xd3, 0xd2,
0x1e, 0xfd, 0x60, 0x40, 0x5e, 0xab, 0x11, 0x5a, 0x49, 0xc7, 0x3d, 0xe2, 0xbb, 0x61, 0xae, 0x8e,
0x33, 0x53, 0xc0, 0xd6, 0x85, 0xef, 0x7f, 0xfb, 0xfb, 0xa7, 0xc9, 0x15, 0x74, 0xd6, 0x49, 0x7d,
0x79, 0xb4, 0x22, 0x39, 0xf7, 0xf4, 0xf3, 0x7b, 0x1f, 0xfd, 0x62, 0xc0, 0xf1, 0x01, 0xd1, 0x47,
0x17, 0x32, 0x60, 0x46, 0x7d, 0x2e, 0xcc, 0xcd, 0xa3, 0x19, 0x6b, 0x66, 0x15, 0xc9, 0x6c, 0x13,
0x9d, 0x4f, 0x33, 0x4b, 0xfe, 0x17, 0x29, 0x82, 0xbf, 0x1a, 0x30, 0x3f, 0xac, 0xdf, 0xc8, 0xce,
0x80, 0xcd, 0xf8, 0x36, 0x98, 0xce, 0x91, 0xed, 0x35, 0xd3, 0xcb, 0x92, 0xe9, 0xfb, 0xa8, 0x92,
0x66, 0xda, 0x4d, 0xce, 0xf4, 0xc8, 0xf6, 0x7f, 0x49, 0xee, 0xa3, 0x07, 0x06, 0xe4, 0xb5, 0x52,
0x67, 0x96, 0x76, 0xf0, 0x13, 0x90, 0x59, 0xda, 0x21, 0xc1, 0xb7, 0x36, 0x25, 0xad, 0x55, 0x74,
0x2e, 0x4d, 0x4b, 0x2b, 0x3f, 0xeb, 0x4b, 0xdd, 0x23, 0x03, 0xf2, 0x5a, 0xb3, 0x33, 0x89, 0x0c,
0x7e, 0x10, 0x32, 0x89, 0x0c, 0x49, 0xbf, 0xb5, 0x25, 0x89, 0x5c, 0x40, 0x1b, 0x69, 0x22, 0x4c,
0x99, 0xf6, 0x78, 0x38, 0xf7, 0x6e, 0x93, 0xfd, 0xfb, 0xe8, 0x2e, 0xe4, 0x84, 0xb4, 0x23, 0x2b,
0xb3, 0x65, 0x0e, 0xfe, 0x0b, 0xe6, 0xd9, 0x43, 0x6d, 0x34, 0x87, 0x0d, 0xc9, 0xe1, 0x2c, 0x3a,
0x33, 0xaa, 0x9b, 0x1a, 0x03, 0x99, 0xf8, 0x06, 0x66, 0x94, 0xba, 0xa1, 0x73, 0x19, 0x9e, 0x07,
0x44, 0xd4, 0x5c, 0x19, 0x63, 0xa5, 0x19, 0x2c, 0x4b, 0x06, 0x26, 0x2a, 0xa6, 0x19, 0x28, 0xf9,
0x44, 0x31, 0xe4, 0xb5, 0x7c, 0xa2, 0xe5, 0xb4, 0xcf, 0x41, 0x65, 0x35, 0xd7, 0xc6, 0xbd, 0x9d,
0x09, 0xae, 0x25, 0x71, 0x17, 0x91, 0x99, 0xc6, 0x25, 0xbc, 0x59, 0x73, 0x05, 0xdc, 0x77, 0x50,
0xe8, 0x53, 0xde, 0x23, 0xa0, 0x8f, 0x88, 0x79, 0x84, 0x74, 0x5b, 0xab, 0x12, 0x7b, 0x19, 0x95,
0x46, 0x60, 0x6b, 0xf3, 0x9a, 0x87, 0x19, 0xfa, 0x16, 0xf2, 0x5a, 0x57, 0x32, 0x7b, 0x6f, 0x50,
0xea, 0x33, 0x7b, 0x6f, 0x48, 0x9e, 0x0e, 0x8b, 0x5e, 0x89, 0x0a, 0x8f, 0xd1, 0x43, 0x03, 0xa0,
0xf7, 0x26, 0xa3, 0xf5, 0xc3, 0x5c, 0xf7, 0x8b, 0x99, 0xb9, 0x71, 0x04, 0x4b, 0xcd, 0x63, 0x45,
0xf2, 0x28, 0xa3, 0xa5, 0x2c, 0x1e, 0x52, 0x26, 0x76, 0xb6, 0x9f, 0x3e, 0x2f, 0x19, 0xcf, 0x9e,
0x97, 0x8c, 0xbf, 0x9e, 0x97, 0x8c, 0xc7, 0x2f, 0x4a, 0x13, 0xcf, 0x5e, 0x94, 0x26, 0x7e, 0x7f,
0x51, 0x9a, 0xf8, 0x7a, 0xcd, 0xf3, 0x79, 0xb3, 0x53, 0xb7, 0x5d, 0x1a, 0x38, 0x2e, 0x89, 0xdc,
0x8b, 0x3e, 0x75, 0x5a, 0xd8, 0xa5, 0xa1, 0xef, 0x36, 0x9c, 0x58, 0xfa, 0xe2, 0xfb, 0x6d, 0xc2,
0xea, 0x33, 0x52, 0x8e, 0xde, 0xfb, 0x37, 0x00, 0x00, 0xff, 0xff, 0x75, 0xcb, 0x4b, 0x26, 0x70,
0x0f, 0x00, 0x00,
// 1371 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0x4d, 0x6f, 0x1b, 0x55,
0x17, 0xce, 0xc4, 0x4e, 0xec, 0x1e, 0xa7, 0x7d, 0xf3, 0xde, 0xa6, 0xd4, 0x1d, 0x12, 0x3b, 0x9d,
0x36, 0x9f, 0x4d, 0x67, 0x88, 0x41, 0x95, 0xa8, 0x84, 0x68, 0x63, 0xa5, 0x05, 0xda, 0xa2, 0x62,
0x22, 0x16, 0x48, 0xc8, 0xba, 0x1e, 0xdf, 0x8e, 0xad, 0xd8, 0x33, 0xae, 0xef, 0xb5, 0x71, 0x5a,
0xca, 0x02, 0x89, 0xaa, 0xa8, 0x9b, 0x4a, 0xb0, 0x46, 0xfd, 0x07, 0xfc, 0x8d, 0x2e, 0x2b, 0xb1,
0x41, 0x2c, 0x0a, 0x6a, 0x10, 0x62, 0xc7, 0x5f, 0x40, 0xf7, 0x63, 0xec, 0x19, 0x8f, 0xc7, 0x4e,
0x51, 0x17, 0xac, 0xe6, 0x7e, 0x9c, 0x7b, 0x9e, 0xe7, 0x9e, 0x7b, 0xe6, 0x3c, 0x07, 0x16, 0x09,
0xab, 0x91, 0x76, 0xb3, 0xee, 0x32, 0x8b, 0x74, 0x9b, 0x56, 0x77, 0xdb, 0xba, 0xdb, 0x21, 0xed,
0x03, 0xb3, 0xd5, 0xf6, 0x98, 0x87, 0xe6, 0xfb, 0xbb, 0x26, 0xe9, 0x36, 0xcd, 0xee, 0xb6, 0xbe,
0xe0, 0x78, 0x8e, 0x27, 0x36, 0x2d, 0x3e, 0x92, 0x76, 0xfa, 0xa6, 0xed, 0xd1, 0xa6, 0x47, 0xad,
0x0a, 0xa6, 0x44, 0x3a, 0xb0, 0xba, 0xdb, 0x15, 0xc2, 0xf0, 0xb6, 0xd5, 0xc2, 0x4e, 0xdd, 0xc5,
0xac, 0xee, 0xb9, 0xca, 0x76, 0xd1, 0xf1, 0x3c, 0xa7, 0x41, 0x2c, 0xdc, 0xaa, 0x5b, 0xd8, 0x75,
0x3d, 0x26, 0x36, 0xa9, 0xda, 0xd5, 0x23, 0x7c, 0x38, 0xb0, 0xdc, 0x3b, 0x13, 0xd9, 0x63, 0x3d,
0xb5, 0x95, 0x57, 0x4e, 0xc5, 0xac, 0xd2, 0xb9, 0x63, 0xb1, 0x7a, 0x93, 0x50, 0x86, 0x9b, 0x2d,
0x69, 0x60, 0xbc, 0x0b, 0x27, 0x3f, 0xe1, 0xbc, 0xae, 0xda, 0xb6, 0xd7, 0x71, 0x59, 0x89, 0xdc,
0xed, 0x10, 0xca, 0x50, 0x16, 0x52, 0xb8, 0x5a, 0x6d, 0x13, 0x4a, 0xb3, 0xda, 0xb2, 0xb6, 0x7e,
0xac, 0xe4, 0x4f, 0x2f, 0xa7, 0x1f, 0x3d, 0xcd, 0x4f, 0xfd, 0xf5, 0x34, 0x3f, 0x65, 0xd8, 0xb0,
0x10, 0x3e, 0x4a, 0x5b, 0x9e, 0x4b, 0x09, 0x3f, 0x5b, 0xc1, 0x0d, 0xec, 0xda, 0xc4, 0x3f, 0xab,
0xa6, 0xe8, 0x4d, 0x38, 0x66, 0x7b, 0x55, 0x52, 0xae, 0x61, 0x5a, 0xcb, 0x4e, 0x8b, 0xbd, 0x34,
0x5f, 0xf8, 0x00, 0xd3, 0x1a, 0x5a, 0x80, 0x19, 0xd7, 0xe3, 0x87, 0x12, 0xcb, 0xda, 0x7a, 0xb2,
0x24, 0x27, 0xc6, 0xfb, 0x70, 0x46, 0x80, 0x14, 0x45, 0x20, 0xff, 0x05, 0xcb, 0x87, 0x1a, 0xe8,
0xa3, 0x3c, 0x28, 0xb2, 0x2b, 0x70, 0x42, 0xbe, 0x51, 0x39, 0xec, 0xe9, 0xb8, 0x5c, 0xbd, 0x2a,
0x17, 0x91, 0x0e, 0x69, 0xca, 0x41, 0x39, 0xbf, 0x69, 0xc1, 0xaf, 0x3f, 0xe7, 0x2e, 0xb0, 0xf4,
0x5a, 0x76, 0x3b, 0xcd, 0x0a, 0x69, 0xab, 0x1b, 0x1c, 0x57, 0xab, 0x1f, 0x8b, 0x45, 0xe3, 0x06,
0x2c, 0x0a, 0x1e, 0x9f, 0xe1, 0x46, 0xbd, 0x8a, 0x99, 0xd7, 0x1e, 0xba, 0xcc, 0x59, 0x98, 0xb3,
0x3d, 0x77, 0x98, 0x47, 0x86, 0xaf, 0x5d, 0x8d, 0xdc, 0xea, 0xb1, 0x06, 0x4b, 0x31, 0xde, 0xd4,
0xc5, 0xd6, 0xe0, 0x7f, 0x3e, 0xab, 0xb0, 0x47, 0x9f, 0xec, 0x6b, 0xbc, 0x9a, 0x9f, 0x44, 0x3b,
0xf2, 0x9d, 0x5f, 0xe5, 0x79, 0xde, 0x52, 0x49, 0xd4, 0x3f, 0x3a, 0x29, 0x89, 0x8c, 0x1b, 0x0a,
0xec, 0x53, 0xe6, 0xb5, 0xb1, 0x33, 0x19, 0x0c, 0xcd, 0x43, 0x62, 0x9f, 0x1c, 0xa8, 0x7c, 0xe3,
0xc3, 0x00, 0xfc, 0x96, 0x82, 0xef, 0x3b, 0x53, 0xf0, 0x0b, 0x30, 0xd3, 0xc5, 0x8d, 0x8e, 0x0f,
0x2e, 0x27, 0xc6, 0x25, 0x98, 0x57, 0xa9, 0x54, 0x7d, 0xa5, 0x4b, 0xae, 0xc1, 0xff, 0x03, 0xe7,
0x14, 0x04, 0x82, 0x24, 0xcf, 0x7d, 0x71, 0x6a, 0xae, 0x24, 0xc6, 0xc6, 0x3d, 0x40, 0xc2, 0x70,
0xaf, 0x77, 0xd3, 0x73, 0xa8, 0x0f, 0x81, 0x20, 0x29, 0xfe, 0x18, 0xe9, 0x5f, 0x8c, 0xd1, 0x35,
0x80, 0x41, 0x05, 0x11, 0x77, 0xcb, 0x14, 0x56, 0x4d, 0x99, 0xb4, 0x26, 0x2f, 0x37, 0xa6, 0xac,
0x57, 0xaa, 0xdc, 0x98, 0xb7, 0x07, 0xa1, 0x2a, 0x05, 0x4e, 0x06, 0x48, 0x7e, 0xa7, 0xa9, 0xc0,
0xfa, 0xe0, 0x8a, 0xe7, 0x06, 0x24, 0x1b, 0x9e, 0xc3, 0x6f, 0x97, 0x58, 0xcf, 0x14, 0x4e, 0x99,
0xc3, 0xa5, 0xcf, 0xbc, 0xe9, 0x39, 0x25, 0x61, 0x82, 0xae, 0x8f, 0x20, 0xb5, 0x36, 0x91, 0x94,
0xc4, 0x09, 0xb2, 0x32, 0x16, 0x54, 0x1c, 0x6e, 0xe3, 0x36, 0x6e, 0xfa, 0x71, 0x30, 0x6e, 0x29,
0x82, 0xfe, 0xaa, 0x22, 0x78, 0x09, 0x66, 0x5b, 0x62, 0x45, 0x04, 0x28, 0x53, 0xc8, 0x46, 0x29,
0xca, 0x13, 0x3b, 0xc9, 0x67, 0x2f, 0xf2, 0x53, 0x25, 0x65, 0x6d, 0xbc, 0x07, 0x27, 0x76, 0x59,
0xad, 0x88, 0x1b, 0x8d, 0x40, 0xa0, 0x71, 0xdb, 0xa1, 0xfe, 0x93, 0xf0, 0x31, 0x3a, 0x0d, 0x29,
0x07, 0xd3, 0xb2, 0x8d, 0x5b, 0xea, 0xef, 0x98, 0x75, 0x30, 0x2d, 0xe2, 0x96, 0xb1, 0x06, 0x27,
0x77, 0x29, 0xab, 0x37, 0x31, 0x23, 0xd7, 0xf1, 0x80, 0xcd, 0x3c, 0x24, 0x1c, 0x2c, 0x5d, 0x24,
0x4b, 0x7c, 0x68, 0xfc, 0x39, 0xed, 0x07, 0xb6, 0x8d, 0x6d, 0xb2, 0xd7, 0xf3, 0xd1, 0xb6, 0x21,
0xd1, 0xa4, 0x8e, 0x22, 0x9d, 0x8f, 0x92, 0xbe, 0x45, 0x9d, 0x5d, 0xbe, 0x46, 0x3a, 0xcd, 0xbd,
0x5e, 0x89, 0xdb, 0xa2, 0x2b, 0x30, 0xc7, 0xb8, 0x93, 0xb2, 0xed, 0xb9, 0x77, 0xea, 0x8e, 0xf8,
0x1b, 0x33, 0x85, 0xa5, 0xe8, 0x59, 0x01, 0x55, 0x14, 0x46, 0xa5, 0x0c, 0x1b, 0x4c, 0x50, 0x11,
0xe6, 0x5a, 0x6d, 0x52, 0x25, 0x36, 0xa1, 0xd4, 0x6b, 0xd3, 0x6c, 0x52, 0xbc, 0xea, 0x44, 0xf4,
0xd0, 0x21, 0x5e, 0xaa, 0x2a, 0x0d, 0xcf, 0xde, 0xf7, 0x8b, 0xc2, 0xcc, 0xb2, 0xb6, 0x9e, 0x28,
0x65, 0xc4, 0x9a, 0x2c, 0x09, 0x68, 0x09, 0x40, 0x9a, 0x88, 0xcc, 0x9d, 0x15, 0x99, 0x7b, 0x4c,
0xac, 0x88, 0x62, 0x5f, 0xf4, 0xb7, 0xb9, 0x1e, 0x65, 0x53, 0xe2, 0x1a, 0xba, 0x29, 0xc5, 0xca,
0xf4, 0xc5, 0xca, 0xdc, 0xf3, 0xc5, 0x6a, 0x27, 0xcd, 0x5f, 0xee, 0xc9, 0x6f, 0x79, 0x4d, 0x39,
0xe1, 0x3b, 0x1f, 0x25, 0xd3, 0xd3, 0xf3, 0x89, 0x52, 0x9a, 0xf5, 0xca, 0x75, 0xb7, 0x4a, 0x7a,
0xc6, 0xa6, 0xfa, 0x99, 0xfb, 0x71, 0x1e, 0xfc, 0x69, 0x55, 0xcc, 0xb0, 0xff, 0xac, 0x7c, 0x6c,
0xfc, 0x30, 0x0d, 0x6f, 0x0c, 0x8c, 0x77, 0xb8, 0xcf, 0xc0, 0xbb, 0xb0, 0x9e, 0x9f, 0xef, 0x93,
0xdf, 0x85, 0xf5, 0xe8, 0x6b, 0x78, 0x97, 0xff, 0x46, 0x48, 0x8d, 0x8b, 0x70, 0x3a, 0x12, 0x95,
0x31, 0x51, 0x3c, 0xd5, 0x2f, 0xfc, 0x94, 0x5c, 0x23, 0x7e, 0x81, 0x31, 0xbe, 0xe8, 0x17, 0x75,
0xb5, 0xac, 0x5c, 0xec, 0x42, 0x9a, 0x57, 0x81, 0xf2, 0x1d, 0xa2, 0x0a, 0xeb, 0xce, 0xe6, 0xaf,
0x2f, 0xf2, 0xab, 0x4e, 0x9d, 0xd5, 0x3a, 0x15, 0xd3, 0xf6, 0x9a, 0x96, 0xea, 0x97, 0xe4, 0xe7,
0x22, 0xad, 0xee, 0x5b, 0xec, 0xa0, 0x45, 0xa8, 0xf9, 0xa1, 0xcb, 0xb8, 0x02, 0x08, 0x77, 0x85,
0xbf, 0xe7, 0x60, 0x46, 0xf8, 0x47, 0xdf, 0x6a, 0x90, 0x52, 0xc2, 0x87, 0x56, 0xa2, 0xd1, 0x1e,
0xd1, 0xd9, 0xe8, 0xab, 0x93, 0xcc, 0x24, 0x57, 0xe3, 0xc2, 0x37, 0x3f, 0xff, 0xf1, 0xfd, 0xf4,
0x0a, 0x3a, 0x67, 0x45, 0xba, 0x2b, 0x25, 0x7e, 0xd6, 0x7d, 0x55, 0xe9, 0x1f, 0xa0, 0x1f, 0x35,
0x38, 0x1e, 0xea, 0x2f, 0xd0, 0x85, 0x18, 0x98, 0x51, 0x7d, 0x8c, 0xbe, 0x75, 0x34, 0x63, 0xc5,
0xac, 0x20, 0x98, 0x6d, 0xa1, 0xcd, 0x28, 0x33, 0xbf, 0x95, 0x89, 0x10, 0xfc, 0x49, 0x83, 0xf9,
0xe1, 0x56, 0x01, 0x99, 0x31, 0xb0, 0x31, 0x1d, 0x8a, 0x6e, 0x1d, 0xd9, 0x5e, 0x31, 0xbd, 0x2c,
0x98, 0xbe, 0x83, 0x0a, 0x51, 0xa6, 0x5d, 0xff, 0xcc, 0x80, 0x6c, 0xb0, 0xfb, 0x79, 0x80, 0x1e,
0x6a, 0x90, 0x52, 0x4d, 0x41, 0xec, 0xd3, 0x86, 0xfb, 0x8d, 0xd8, 0xa7, 0x1d, 0xea, 0x2d, 0x8c,
0x2d, 0x41, 0x6b, 0x15, 0x9d, 0x8f, 0xd2, 0x52, 0x4d, 0x06, 0x0d, 0x84, 0xee, 0xb1, 0x06, 0x29,
0xd5, 0x1e, 0xc4, 0x12, 0x09, 0xf7, 0x22, 0xb1, 0x44, 0x86, 0xba, 0x0c, 0x63, 0x5b, 0x10, 0xb9,
0x80, 0x36, 0xa2, 0x44, 0xa8, 0x34, 0x1d, 0xf0, 0xb0, 0xee, 0xef, 0x93, 0x83, 0x07, 0xe8, 0x1e,
0x24, 0x79, 0x17, 0x81, 0x8c, 0xd8, 0x94, 0xe9, 0xb7, 0x26, 0xfa, 0xb9, 0xb1, 0x36, 0x8a, 0xc3,
0x86, 0xe0, 0x70, 0x0e, 0x9d, 0x1d, 0x95, 0x4d, 0xd5, 0x50, 0x24, 0xbe, 0x84, 0x59, 0x29, 0xa4,
0xe8, 0x7c, 0x8c, 0xe7, 0x90, 0x5e, 0xeb, 0x2b, 0x13, 0xac, 0x14, 0x83, 0x65, 0xc1, 0x40, 0x47,
0xd9, 0x28, 0x03, 0xa9, 0xd4, 0xa8, 0x07, 0x29, 0xa5, 0xd4, 0x68, 0x39, 0xea, 0x33, 0x2c, 0xe2,
0xfa, 0xda, 0xa4, 0x8a, 0xed, 0xe3, 0x1a, 0x02, 0x77, 0x11, 0xe9, 0x51, 0x5c, 0xc2, 0x6a, 0x65,
0x9b, 0xc3, 0x7d, 0x0d, 0x99, 0x80, 0xc8, 0x1f, 0x01, 0x7d, 0xc4, 0x9d, 0x47, 0x74, 0x09, 0xc6,
0xaa, 0xc0, 0x5e, 0x46, 0xb9, 0x11, 0xd8, 0xca, 0xbc, 0xec, 0x60, 0x8a, 0xbe, 0x82, 0x94, 0x52,
0xb3, 0xd8, 0xdc, 0x0b, 0x77, 0x15, 0xb1, 0xb9, 0x37, 0x24, 0x8a, 0xe3, 0x6e, 0x2f, 0xa5, 0x8c,
0xf5, 0xd0, 0x23, 0x0d, 0x60, 0xa0, 0x04, 0x68, 0x7d, 0x9c, 0xeb, 0xa0, 0x84, 0xea, 0x1b, 0x47,
0xb0, 0x54, 0x3c, 0x56, 0x04, 0x8f, 0x3c, 0x5a, 0x8a, 0xe3, 0x21, 0xc4, 0x89, 0x07, 0x42, 0xa9,
0xc9, 0x98, 0x6a, 0x10, 0x14, 0xa1, 0x31, 0xd5, 0x20, 0x24, 0x4a, 0xe3, 0x02, 0xe1, 0x8b, 0xd5,
0xce, 0x95, 0x67, 0x2f, 0x73, 0xda, 0xf3, 0x97, 0x39, 0xed, 0xf7, 0x97, 0x39, 0xed, 0xc9, 0x61,
0x6e, 0xea, 0xf9, 0x61, 0x6e, 0xea, 0x97, 0xc3, 0xdc, 0xd4, 0xe7, 0x41, 0xf1, 0x22, 0x5d, 0xae,
0x5d, 0x03, 0x2f, 0x3d, 0xe1, 0x47, 0x08, 0x58, 0x65, 0x56, 0x28, 0xf0, 0xdb, 0xff, 0x04, 0x00,
0x00, 0xff, 0xff, 0x7d, 0x85, 0x8e, 0xb2, 0x58, 0x10, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -1309,6 +1383,9 @@ type QueryClient interface {
TraceTx(ctx context.Context, in *QueryTraceTxRequest, opts ...grpc.CallOption) (*QueryTraceTxResponse, error)
// TraceBlock implements the `debug_traceBlockByNumber` and `debug_traceBlockByHash` rpc api
TraceBlock(ctx context.Context, in *QueryTraceBlockRequest, opts ...grpc.CallOption) (*QueryTraceBlockResponse, error)
// BaseFee queries the base fee of the parent block of the current block,
// it's similar to feemarket module's method, but also checks london hardfork status.
BaseFee(ctx context.Context, in *QueryBaseFeeRequest, opts ...grpc.CallOption) (*QueryBaseFeeResponse, error)
}
type queryClient struct {
@@ -1418,6 +1495,15 @@ func (c *queryClient) TraceBlock(ctx context.Context, in *QueryTraceBlockRequest
return out, nil
}
func (c *queryClient) BaseFee(ctx context.Context, in *QueryBaseFeeRequest, opts ...grpc.CallOption) (*QueryBaseFeeResponse, error) {
out := new(QueryBaseFeeResponse)
err := c.cc.Invoke(ctx, "/ethermint.evm.v1.Query/BaseFee", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// QueryServer is the server API for Query service.
type QueryServer interface {
// Account queries an Ethereum account.
@@ -1444,6 +1530,9 @@ type QueryServer interface {
TraceTx(context.Context, *QueryTraceTxRequest) (*QueryTraceTxResponse, error)
// TraceBlock implements the `debug_traceBlockByNumber` and `debug_traceBlockByHash` rpc api
TraceBlock(context.Context, *QueryTraceBlockRequest) (*QueryTraceBlockResponse, error)
// BaseFee queries the base fee of the parent block of the current block,
// it's similar to feemarket module's method, but also checks london hardfork status.
BaseFee(context.Context, *QueryBaseFeeRequest) (*QueryBaseFeeResponse, error)
}
// UnimplementedQueryServer can be embedded to have forward compatible implementations.
@@ -1483,6 +1572,9 @@ func (*UnimplementedQueryServer) TraceTx(ctx context.Context, req *QueryTraceTxR
func (*UnimplementedQueryServer) TraceBlock(ctx context.Context, req *QueryTraceBlockRequest) (*QueryTraceBlockResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method TraceBlock not implemented")
}
func (*UnimplementedQueryServer) BaseFee(ctx context.Context, req *QueryBaseFeeRequest) (*QueryBaseFeeResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method BaseFee not implemented")
}
func RegisterQueryServer(s grpc1.Server, srv QueryServer) {
s.RegisterService(&_Query_serviceDesc, srv)
@@ -1686,6 +1778,24 @@ func _Query_TraceBlock_Handler(srv interface{}, ctx context.Context, dec func(in
return interceptor(ctx, in, info, handler)
}
func _Query_BaseFee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(QueryBaseFeeRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(QueryServer).BaseFee(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/ethermint.evm.v1.Query/BaseFee",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(QueryServer).BaseFee(ctx, req.(*QueryBaseFeeRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Query_serviceDesc = grpc.ServiceDesc{
ServiceName: "ethermint.evm.v1.Query",
HandlerType: (*QueryServer)(nil),
@@ -1734,6 +1844,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{
MethodName: "TraceBlock",
Handler: _Query_TraceBlock_Handler,
},
{
MethodName: "BaseFee",
Handler: _Query_BaseFee_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "ethermint/evm/v1/query.proto",
@@ -2414,11 +2528,6 @@ func (m *QueryTraceTxRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i--
dAtA[i] = 0x1a
}
if m.TxIndex != 0 {
i = encodeVarintQuery(dAtA, i, uint64(m.TxIndex))
i--
dAtA[i] = 0x10
}
if m.Msg != nil {
{
size, err := m.Msg.MarshalToSizedBuffer(dAtA[:i])
@@ -2563,6 +2672,64 @@ func (m *QueryTraceBlockResponse) MarshalToSizedBuffer(dAtA []byte) (int, error)
return len(dAtA) - i, nil
}
func (m *QueryBaseFeeRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *QueryBaseFeeRequest) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *QueryBaseFeeRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
return len(dAtA) - i, nil
}
func (m *QueryBaseFeeResponse) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *QueryBaseFeeResponse) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *QueryBaseFeeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.BaseFee != nil {
{
size := m.BaseFee.Size()
i -= size
if _, err := m.BaseFee.MarshalTo(dAtA[i:]); err != nil {
return 0, err
}
i = encodeVarintQuery(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintQuery(dAtA []byte, offset int, v uint64) int {
offset -= sovQuery(v)
base := offset
@@ -2847,9 +3014,6 @@ func (m *QueryTraceTxRequest) Size() (n int) {
l = m.Msg.Size()
n += 1 + l + sovQuery(uint64(l))
}
if m.TxIndex != 0 {
n += 1 + sovQuery(uint64(m.TxIndex))
}
if m.TraceConfig != nil {
l = m.TraceConfig.Size()
n += 1 + l + sovQuery(uint64(l))
@@ -2926,6 +3090,28 @@ func (m *QueryTraceBlockResponse) Size() (n int) {
return n
}
func (m *QueryBaseFeeRequest) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
return n
}
func (m *QueryBaseFeeResponse) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.BaseFee != nil {
l = m.BaseFee.Size()
n += 1 + l + sovQuery(uint64(l))
}
return n
}
func sovQuery(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
@@ -4685,25 +4871,6 @@ func (m *QueryTraceTxRequest) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field TxIndex", wireType)
}
m.TxIndex = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.TxIndex |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field TraceConfig", wireType)
@@ -5251,6 +5418,142 @@ func (m *QueryTraceBlockResponse) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *QueryBaseFeeRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: QueryBaseFeeRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: QueryBaseFeeRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
default:
iNdEx = preIndex
skippy, err := skipQuery(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthQuery
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *QueryBaseFeeResponse) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: QueryBaseFeeResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: QueryBaseFeeResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field BaseFee", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthQuery
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthQuery
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
var v github_com_cosmos_cosmos_sdk_types.Int
m.BaseFee = &v
if err := m.BaseFee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipQuery(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthQuery
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipQuery(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
+62
View File
@@ -539,6 +539,24 @@ func local_request_Query_TraceBlock_0(ctx context.Context, marshaler runtime.Mar
}
func request_Query_BaseFee_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryBaseFeeRequest
var metadata runtime.ServerMetadata
msg, err := client.BaseFee(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_BaseFee_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryBaseFeeRequest
var metadata runtime.ServerMetadata
msg, err := server.BaseFee(ctx, &protoReq)
return msg, metadata, err
}
// RegisterQueryHandlerServer registers the http handlers for service Query to "mux".
// UnaryRPC :call QueryServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
@@ -765,6 +783,26 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
})
mux.Handle("GET", pattern_Query_BaseFee_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_BaseFee_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_BaseFee_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
@@ -1026,6 +1064,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
})
mux.Handle("GET", pattern_Query_BaseFee_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_BaseFee_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_BaseFee_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
@@ -1051,6 +1109,8 @@ var (
pattern_Query_TraceTx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"ethermint", "evm", "v1", "trace_tx"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_TraceBlock_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"ethermint", "evm", "v1", "trace_block"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_BaseFee_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"ethermint", "evm", "v1", "base_fee"}, "", runtime.AssumeColonVerbOpt(true)))
)
var (
@@ -1075,4 +1135,6 @@ var (
forward_Query_TraceTx_0 = runtime.ForwardResponseMessage
forward_Query_TraceBlock_0 = runtime.ForwardResponseMessage
forward_Query_BaseFee_0 = runtime.ForwardResponseMessage
)
+14 -78
View File
@@ -1,7 +1,6 @@
package types
import (
"fmt"
"math/big"
"os"
"time"
@@ -31,7 +30,7 @@ func NewTracer(tracer string, msg core.Message, cfg *params.ChainConfig, height
switch tracer {
case TracerAccessList:
preCompiles := vm.ActivePrecompiles(cfg.Rules(big.NewInt(height), cfg.MergeForkBlock != nil))
preCompiles := vm.ActivePrecompiles(cfg.Rules(big.NewInt(height), cfg.MergeNetsplitBlock != nil))
return logger.NewAccessListTracer(msg.AccessList(), msg.From(), *msg.To(), preCompiles)
case TracerJSON:
return logger.NewJSONLogger(logCfg, os.Stderr)
@@ -44,87 +43,12 @@ func NewTracer(tracer string, msg core.Message, cfg *params.ChainConfig, height
}
}
// TxTraceTask represents a single transaction trace task when an entire block
// is being traced.
type TxTraceTask struct {
Index int // Transaction offset in the block
}
// TxTraceResult is the result of a single transaction trace during a block trace.
type TxTraceResult struct {
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
Error string `json:"error,omitempty"` // Trace failure produced by the tracer
}
// ExecutionResult groups all structured logs emitted by the EVM
// while replaying a transaction in debug mode as well as transaction
// execution status, the amount of gas used and the return value
type ExecutionResult struct {
Gas uint64 `json:"gas"`
Failed bool `json:"failed"`
ReturnValue string `json:"returnValue"`
StructLogs []StructLogRes `json:"structLogs"`
}
// StructLogRes stores a structured log emitted by the EVM while replaying a
// transaction in debug mode. Taken from go-ethereum
type StructLogRes struct {
Pc uint64 `json:"pc"`
Op string `json:"op"`
Gas uint64 `json:"gas"`
GasCost uint64 `json:"gasCost"`
Depth int `json:"depth"`
Error string `json:"error,omitempty"`
Stack *[]string `json:"stack,omitempty"`
Memory *[]string `json:"memory,omitempty"`
Storage *map[string]string `json:"storage,omitempty"`
}
// FormatLogs formats EVM returned structured logs for json output
func FormatLogs(logs []logger.StructLog) []StructLogRes {
formatted := make([]StructLogRes, len(logs))
for index, trace := range logs {
formatted[index] = StructLogRes{
Pc: trace.Pc,
Op: trace.Op.String(),
Gas: trace.Gas,
GasCost: trace.GasCost,
Depth: trace.Depth,
Error: trace.ErrorString(),
}
if trace.Stack != nil {
stack := make([]string, len(trace.Stack))
for i, stackValue := range trace.Stack {
stack[i] = fmt.Sprintf("%x", stackValue)
}
formatted[index].Stack = &stack
}
if trace.Memory != nil {
memory := make([]string, 0, (len(trace.Memory)+31)/32)
for i, n := 0, len(trace.Memory); i < n; {
end := i + 32
if end >= n {
end = n
}
memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:end]))
i = end
}
formatted[index].Memory = &memory
}
if trace.Storage != nil {
storage := make(map[string]string)
for i, storageValue := range trace.Storage {
storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue)
}
formatted[index].Storage = &storage
}
}
return formatted
}
var _ vm.EVMLogger = &NoOpTracer{}
// NoOpTracer is an empty implementation of vm.Tracer interface
@@ -136,7 +60,13 @@ func NewNoOpTracer() *NoOpTracer {
}
// CaptureStart implements vm.Tracer interface
func (dt NoOpTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
func (dt NoOpTracer) CaptureStart(env *vm.EVM,
from common.Address,
to common.Address,
create bool,
input []byte,
gas uint64,
value *big.Int) {
}
// CaptureState implements vm.Tracer interface
@@ -156,3 +86,9 @@ func (dt NoOpTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.
// CaptureExit implements vm.Tracer interface
func (dt NoOpTracer) CaptureExit(output []byte, gasUsed uint64, err error) {}
// CaptureTxStart implements vm.Tracer interface
func (dt NoOpTracer) CaptureTxStart(gasLimit uint64) {}
// CaptureTxEnd implements vm.Tracer interface
func (dt NoOpTracer) CaptureTxEnd(restGas uint64) {}
-74
View File
@@ -1,85 +1,11 @@
package types
import (
"fmt"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/holiman/uint256"
"github.com/stretchr/testify/require"
)
func TestFormatLogs(t *testing.T) {
zeroUint256 := []uint256.Int{*uint256.NewInt(0)}
zeroByte := []byte{5}
zeroStorage := make(map[string]string)
testCases := []struct {
name string
logs []logger.StructLog
exp []StructLogRes
}{
{
"empty logs",
[]logger.StructLog{},
[]StructLogRes{},
},
{
"non-empty stack",
[]logger.StructLog{
{
Stack: zeroUint256,
},
},
[]StructLogRes{
{
Pc: uint64(0),
Op: "STOP",
Stack: &[]string{fmt.Sprintf("%x", zeroUint256[0])},
},
},
},
{
"non-empty memory",
[]logger.StructLog{
{
Memory: zeroByte,
},
},
[]StructLogRes{
{
Pc: uint64(0),
Op: "STOP",
Memory: &[]string{"05"},
},
},
},
{
"non-empty storage",
[]logger.StructLog{
{
Storage: make(map[common.Hash]common.Hash),
},
},
[]StructLogRes{
{
Pc: uint64(0),
Op: "STOP",
Storage: &zeroStorage,
},
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actual := FormatLogs(tc.logs)
require.Equal(t, tc.exp, actual)
})
}
}
func TestNewNoOpTracer(t *testing.T) {
require.Equal(t, &NoOpTracer{}, NewNoOpTracer())
}
+58 -56
View File
@@ -37,7 +37,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type MsgEthereumTx struct {
// inner transaction data
Data *types.Any `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
// encoded storage size of the transaction
// DEPRECATED: encoded storage size of the transaction
Size_ float64 `protobuf:"fixed64,2,opt,name=size,proto3" json:"-"`
// transaction hash in hex format
Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty" rlp:"-"`
@@ -81,6 +81,8 @@ func (m *MsgEthereumTx) XXX_DiscardUnknown() {
var xxx_messageInfo_MsgEthereumTx proto.InternalMessageInfo
// LegacyTx is the transaction data of regular Ethereum transactions.
// NOTE: All non-protected transactions (i.e non EIP155 signed) will fail if the
// AllowUnprotectedTxs parameter is disabled.
type LegacyTx struct {
// nonce corresponds to the account nonce (transaction sequence).
Nonce uint64 `protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"`
@@ -352,61 +354,61 @@ func init() {
func init() { proto.RegisterFile("ethermint/evm/v1/tx.proto", fileDescriptor_f75ac0a12d075f21) }
var fileDescriptor_f75ac0a12d075f21 = []byte{
// 859 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0x41, 0x8f, 0xdb, 0x44,
0x14, 0xce, 0x24, 0x4e, 0xec, 0x4c, 0x42, 0x55, 0x59, 0x5b, 0xc9, 0x1b, 0xd1, 0x38, 0xb2, 0x04,
0x0d, 0x48, 0xb1, 0xd5, 0x85, 0xd3, 0x9e, 0xd8, 0x74, 0xb7, 0x55, 0xab, 0xad, 0x40, 0x56, 0xb8,
0xd0, 0x43, 0x34, 0xeb, 0xcc, 0x3a, 0x23, 0xe2, 0x19, 0xcb, 0x33, 0xb1, 0x1c, 0x24, 0x2e, 0x88,
0x03, 0x37, 0x90, 0xf8, 0x03, 0x1c, 0x38, 0x71, 0x85, 0x1f, 0xc0, 0xb1, 0xc7, 0x0a, 0x2e, 0x88,
0x83, 0x41, 0x59, 0x4e, 0x7b, 0x83, 0x5f, 0x80, 0x66, 0xec, 0xec, 0x6e, 0x88, 0x52, 0xa0, 0x2c,
0xea, 0x29, 0xf3, 0xfc, 0xbd, 0x79, 0xf3, 0xde, 0xfb, 0xbe, 0xbc, 0x07, 0x77, 0xb1, 0x98, 0xe2,
0x24, 0x22, 0x54, 0x78, 0x38, 0x8d, 0xbc, 0xf4, 0xae, 0x27, 0x32, 0x37, 0x4e, 0x98, 0x60, 0xe6,
0xcd, 0x0b, 0xc8, 0xc5, 0x69, 0xe4, 0xa6, 0x77, 0x3b, 0x3b, 0x21, 0x0b, 0x99, 0x02, 0x3d, 0x79,
0x2a, 0xfc, 0x3a, 0xaf, 0x86, 0x8c, 0x85, 0x33, 0xec, 0xa1, 0x98, 0x78, 0x88, 0x52, 0x26, 0x90,
0x20, 0x8c, 0xf2, 0x12, 0xdd, 0x2d, 0x51, 0x65, 0x9d, 0xcc, 0x4f, 0x3d, 0x44, 0x17, 0x2b, 0x28,
0x60, 0x3c, 0x62, 0x7c, 0x5c, 0x44, 0x2c, 0x8c, 0x12, 0xea, 0x6c, 0xa4, 0x25, 0x53, 0x50, 0x98,
0xf3, 0x39, 0x80, 0xaf, 0x3c, 0xe6, 0xe1, 0x91, 0xf4, 0xc0, 0xf3, 0x68, 0x94, 0x99, 0x7d, 0xa8,
0x4d, 0x90, 0x40, 0x16, 0xe8, 0x81, 0x7e, 0x6b, 0x6f, 0xc7, 0x2d, 0x9e, 0x74, 0x57, 0x4f, 0xba,
0x07, 0x74, 0xe1, 0x2b, 0x0f, 0x73, 0x17, 0x6a, 0x9c, 0x7c, 0x84, 0xad, 0x6a, 0x0f, 0xf4, 0xc1,
0xb0, 0x7e, 0x9e, 0xdb, 0x60, 0xe0, 0xab, 0x4f, 0xa6, 0x0d, 0xb5, 0x29, 0xe2, 0x53, 0xab, 0xd6,
0x03, 0xfd, 0xe6, 0xb0, 0xf5, 0x47, 0x6e, 0xeb, 0xc9, 0x2c, 0xde, 0x77, 0x06, 0x8e, 0xaf, 0x00,
0xd3, 0x84, 0xda, 0x69, 0xc2, 0x22, 0x4b, 0x93, 0x0e, 0xbe, 0x3a, 0xef, 0x6b, 0x9f, 0x7d, 0x65,
0x57, 0x9c, 0x6f, 0xab, 0xd0, 0x38, 0xc6, 0x21, 0x0a, 0x16, 0xa3, 0xcc, 0xdc, 0x81, 0x75, 0xca,
0x68, 0x80, 0x55, 0x36, 0x9a, 0x5f, 0x18, 0xe6, 0x03, 0xd8, 0x0c, 0x91, 0x2c, 0x95, 0x04, 0xc5,
0xeb, 0xcd, 0xe1, 0x9b, 0x3f, 0xe7, 0xf6, 0xeb, 0x21, 0x11, 0xd3, 0xf9, 0x89, 0x1b, 0xb0, 0xa8,
0x6c, 0x40, 0xf9, 0x33, 0xe0, 0x93, 0x0f, 0x3d, 0xb1, 0x88, 0x31, 0x77, 0x1f, 0x52, 0xe1, 0x1b,
0x21, 0xe2, 0xef, 0xc9, 0xbb, 0x66, 0x17, 0xd6, 0x42, 0xc4, 0x55, 0x96, 0xda, 0xb0, 0xbd, 0xcc,
0x6d, 0xe3, 0x01, 0xe2, 0xc7, 0x24, 0x22, 0xc2, 0x97, 0x80, 0x79, 0x03, 0x56, 0x05, 0x2b, 0x73,
0xac, 0x0a, 0x66, 0x3e, 0x82, 0xf5, 0x14, 0xcd, 0xe6, 0xd8, 0xaa, 0xab, 0x47, 0xdf, 0xfe, 0xe7,
0x8f, 0x2e, 0x73, 0xbb, 0x71, 0x10, 0xb1, 0x39, 0x15, 0x7e, 0x11, 0x42, 0x76, 0x40, 0xf5, 0xb9,
0xd1, 0x03, 0xfd, 0x76, 0xd9, 0xd1, 0x36, 0x04, 0xa9, 0xa5, 0xab, 0x0f, 0x20, 0x95, 0x56, 0x62,
0x19, 0x85, 0x95, 0x48, 0x8b, 0x5b, 0xcd, 0xc2, 0xe2, 0xfb, 0x37, 0x64, 0xaf, 0x7e, 0xf8, 0x6e,
0xd0, 0x18, 0x65, 0x87, 0x48, 0x20, 0xe7, 0xf7, 0x1a, 0x6c, 0x1f, 0x04, 0x01, 0xe6, 0xfc, 0x98,
0x70, 0x31, 0xca, 0xcc, 0x27, 0xd0, 0x08, 0xa6, 0x88, 0xd0, 0x31, 0x99, 0xa8, 0xe6, 0x35, 0x87,
0xef, 0xfc, 0xab, 0x6c, 0xf5, 0x7b, 0xf2, 0xf6, 0xc3, 0xc3, 0xf3, 0xdc, 0xd6, 0x83, 0xe2, 0xe8,
0x97, 0x87, 0xc9, 0x25, 0x2d, 0xd5, 0xad, 0xb4, 0xd4, 0xfe, 0x3b, 0x2d, 0xda, 0xf3, 0x69, 0xa9,
0x6f, 0xd2, 0xd2, 0xb8, 0x3e, 0x5a, 0xf4, 0x2b, 0xb4, 0x3c, 0x81, 0x06, 0x52, 0xbd, 0xc5, 0xdc,
0x32, 0x7a, 0xb5, 0x7e, 0x6b, 0xef, 0xb6, 0xfb, 0xd7, 0xff, 0xb3, 0x5b, 0x74, 0x7f, 0x34, 0x8f,
0x67, 0x78, 0xd8, 0x7b, 0x9a, 0xdb, 0x95, 0xf3, 0xdc, 0x86, 0xe8, 0x82, 0x92, 0x6f, 0x7e, 0xb1,
0xe1, 0x25, 0x41, 0xfe, 0x45, 0xc0, 0x82, 0xf3, 0xe6, 0x1a, 0xe7, 0x70, 0x8d, 0xf3, 0xd6, 0x36,
0xce, 0xbf, 0xd7, 0x60, 0xfb, 0x70, 0x41, 0x51, 0x44, 0x82, 0xfb, 0x18, 0xbf, 0x1c, 0xce, 0x1f,
0xc1, 0x96, 0xe4, 0x5c, 0x90, 0x78, 0x1c, 0xa0, 0xf8, 0x05, 0x58, 0x97, 0x92, 0x19, 0x91, 0xf8,
0x1e, 0x8a, 0x57, 0xb1, 0x4e, 0x31, 0x56, 0xb1, 0xb4, 0x17, 0x8a, 0x75, 0x1f, 0x63, 0x19, 0xab,
0x94, 0x50, 0xfd, 0xf9, 0x12, 0x6a, 0x6c, 0x4a, 0x48, 0xbf, 0x3e, 0x09, 0x19, 0x5b, 0x24, 0xd4,
0xfc, 0x5f, 0x24, 0x04, 0xd7, 0x24, 0xd4, 0x5a, 0x93, 0x50, 0x7b, 0x9b, 0x84, 0x1c, 0xd8, 0x39,
0xca, 0x04, 0xa6, 0x9c, 0x30, 0xfa, 0x6e, 0xac, 0x56, 0xcd, 0xe5, 0x2a, 0x28, 0x07, 0xf2, 0xd7,
0x00, 0xde, 0x5a, 0x5b, 0x11, 0x3e, 0xe6, 0x31, 0xa3, 0x5c, 0x15, 0xaa, 0xa6, 0x3c, 0x28, 0x86,
0xb8, 0x1a, 0xec, 0x6f, 0x40, 0x6d, 0xc6, 0x42, 0x6e, 0x55, 0x55, 0x91, 0xb7, 0x36, 0x8b, 0x3c,
0x66, 0xa1, 0xaf, 0x5c, 0xcc, 0x9b, 0xb0, 0x96, 0x60, 0xa1, 0x34, 0xd3, 0xf6, 0xe5, 0xd1, 0xdc,
0x85, 0x46, 0x1a, 0x8d, 0x71, 0x92, 0xb0, 0xa4, 0x9c, 0xba, 0x7a, 0x1a, 0x1d, 0x49, 0x53, 0x42,
0x52, 0x1c, 0x73, 0x8e, 0x27, 0x05, 0xab, 0xbe, 0x1e, 0x22, 0xfe, 0x3e, 0xc7, 0x93, 0x22, 0xcd,
0xbd, 0x4f, 0x01, 0xac, 0x3d, 0xe6, 0xa1, 0xf9, 0x31, 0x84, 0x57, 0xb6, 0x99, 0xbd, 0x99, 0xc0,
0x5a, 0x2d, 0x9d, 0x3b, 0x7f, 0xe3, 0xb0, 0x2a, 0xd6, 0x79, 0xed, 0x93, 0x1f, 0x7f, 0xfb, 0xb2,
0x6a, 0x3b, 0xb7, 0xbd, 0xcd, 0x75, 0x5a, 0x7a, 0x8f, 0x45, 0x36, 0x3c, 0x78, 0xba, 0xec, 0x82,
0x67, 0xcb, 0x2e, 0xf8, 0x75, 0xd9, 0x05, 0x5f, 0x9c, 0x75, 0x2b, 0xcf, 0xce, 0xba, 0x95, 0x9f,
0xce, 0xba, 0x95, 0x0f, 0xee, 0x5c, 0xd5, 0x13, 0x4e, 0x82, 0x01, 0x61, 0xde, 0x0c, 0x05, 0x8c,
0x92, 0x60, 0xe2, 0x65, 0x2a, 0x96, 0x12, 0xd5, 0x49, 0x43, 0xed, 0xda, 0xb7, 0xfe, 0x0c, 0x00,
0x00, 0xff, 0xff, 0x91, 0xe5, 0xb2, 0x95, 0x4f, 0x08, 0x00, 0x00,
// 851 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0x4f, 0x6f, 0xe3, 0x44,
0x14, 0xcf, 0x24, 0x4e, 0xec, 0x4c, 0xc2, 0x6a, 0x65, 0x75, 0x25, 0x27, 0x62, 0xe3, 0xc8, 0x12,
0x10, 0x90, 0x62, 0x6b, 0x0b, 0xa7, 0x9e, 0xb6, 0xd9, 0xfe, 0x51, 0xab, 0x54, 0x20, 0x2b, 0x5c,
0xe8, 0x21, 0x9a, 0x3a, 0x53, 0xc7, 0x22, 0xf6, 0x58, 0x9e, 0x89, 0xe5, 0x20, 0x71, 0x41, 0x1c,
0xb8, 0x81, 0xc4, 0x17, 0xe0, 0xc0, 0x89, 0x2b, 0x7c, 0x00, 0x8e, 0x3d, 0x56, 0x70, 0x41, 0x1c,
0x0c, 0x4a, 0x39, 0xf5, 0x06, 0x9f, 0x00, 0xcd, 0xd8, 0x69, 0x1a, 0xa2, 0x14, 0x28, 0x45, 0x7b,
0xca, 0x3c, 0xff, 0xde, 0xbc, 0x79, 0xef, 0xfd, 0x7e, 0x79, 0x0f, 0x36, 0x30, 0x1b, 0xe3, 0xc8,
0xf7, 0x02, 0x66, 0xe1, 0xd8, 0xb7, 0xe2, 0x67, 0x16, 0x4b, 0xcc, 0x30, 0x22, 0x8c, 0xa8, 0x8f,
0x6f, 0x20, 0x13, 0xc7, 0xbe, 0x19, 0x3f, 0x6b, 0x6e, 0xb9, 0xc4, 0x25, 0x02, 0xb4, 0xf8, 0x29,
0xf3, 0x6b, 0xbe, 0xea, 0x12, 0xe2, 0x4e, 0xb0, 0x85, 0x42, 0xcf, 0x42, 0x41, 0x40, 0x18, 0x62,
0x1e, 0x09, 0x68, 0x8e, 0x36, 0x72, 0x54, 0x58, 0x67, 0xd3, 0x73, 0x0b, 0x05, 0xb3, 0x05, 0xe4,
0x10, 0xea, 0x13, 0x3a, 0xcc, 0x22, 0x66, 0x46, 0x0e, 0x35, 0xd7, 0xd2, 0xe2, 0x29, 0x08, 0xcc,
0xf8, 0x1c, 0xc0, 0x57, 0x4e, 0xa8, 0xbb, 0xcf, 0x3d, 0xf0, 0xd4, 0x1f, 0x24, 0x6a, 0x07, 0x4a,
0x23, 0xc4, 0x90, 0x06, 0xda, 0xa0, 0x53, 0xdb, 0xde, 0x32, 0xb3, 0x27, 0xcd, 0xc5, 0x93, 0xe6,
0x6e, 0x30, 0xb3, 0x85, 0x87, 0xda, 0x80, 0x12, 0xf5, 0x3e, 0xc2, 0x5a, 0xb1, 0x0d, 0x3a, 0xa0,
0x57, 0xbe, 0x4e, 0x75, 0xd0, 0xb5, 0xc5, 0x27, 0x55, 0x87, 0xd2, 0x18, 0xd1, 0xb1, 0x56, 0x6a,
0x83, 0x4e, 0xb5, 0x57, 0xfb, 0x23, 0xd5, 0xe5, 0x68, 0x12, 0xee, 0x18, 0x5d, 0xc3, 0x16, 0x80,
0xaa, 0x42, 0xe9, 0x3c, 0x22, 0xbe, 0x26, 0x71, 0x07, 0x5b, 0x9c, 0x77, 0xa4, 0xcf, 0xbe, 0xd2,
0x0b, 0xc6, 0xb7, 0x45, 0xa8, 0xf4, 0xb1, 0x8b, 0x9c, 0xd9, 0x20, 0x51, 0xb7, 0x60, 0x39, 0x20,
0x81, 0x83, 0x45, 0x36, 0x92, 0x9d, 0x19, 0xea, 0x21, 0xac, 0xba, 0x88, 0x97, 0xea, 0x39, 0xd9,
0xeb, 0xd5, 0xde, 0x5b, 0x3f, 0xa7, 0xfa, 0xeb, 0xae, 0xc7, 0xc6, 0xd3, 0x33, 0xd3, 0x21, 0x7e,
0xde, 0x80, 0xfc, 0xa7, 0x4b, 0x47, 0x1f, 0x5a, 0x6c, 0x16, 0x62, 0x6a, 0x1e, 0x05, 0xcc, 0x56,
0x5c, 0x44, 0xdf, 0xe3, 0x77, 0xd5, 0x16, 0x2c, 0xb9, 0x88, 0x8a, 0x2c, 0xa5, 0x5e, 0x7d, 0x9e,
0xea, 0xca, 0x21, 0xa2, 0x7d, 0xcf, 0xf7, 0x98, 0xcd, 0x01, 0xf5, 0x11, 0x2c, 0x32, 0x92, 0xe7,
0x58, 0x64, 0x44, 0x3d, 0x86, 0xe5, 0x18, 0x4d, 0xa6, 0x58, 0x2b, 0x8b, 0x47, 0xdf, 0xf9, 0xe7,
0x8f, 0xce, 0x53, 0xbd, 0xb2, 0xeb, 0x93, 0x69, 0xc0, 0xec, 0x2c, 0x04, 0xef, 0x80, 0xe8, 0x73,
0xa5, 0x0d, 0x3a, 0xf5, 0xbc, 0xa3, 0x75, 0x08, 0x62, 0x4d, 0x16, 0x1f, 0x40, 0xcc, 0xad, 0x48,
0x53, 0x32, 0x2b, 0xe2, 0x16, 0xd5, 0xaa, 0x99, 0x45, 0x77, 0x1e, 0xf1, 0x5e, 0xfd, 0xf0, 0x5d,
0xb7, 0x32, 0x48, 0xf6, 0x10, 0x43, 0xc6, 0xef, 0x25, 0x58, 0xdf, 0x75, 0x1c, 0x4c, 0x69, 0xdf,
0xa3, 0x6c, 0x90, 0xa8, 0xa7, 0x50, 0x71, 0xc6, 0xc8, 0x0b, 0x86, 0xde, 0x48, 0x34, 0xaf, 0xda,
0x7b, 0xfe, 0xaf, 0xb2, 0x95, 0x5f, 0xf0, 0xdb, 0x47, 0x7b, 0xd7, 0xa9, 0x2e, 0x3b, 0xd9, 0xd1,
0xce, 0x0f, 0xa3, 0x25, 0x2d, 0xc5, 0x8d, 0xb4, 0x94, 0xfe, 0x3b, 0x2d, 0xd2, 0xdd, 0xb4, 0x94,
0xd7, 0x69, 0xa9, 0x3c, 0x1c, 0x2d, 0xf2, 0x2d, 0x5a, 0x4e, 0xa1, 0x82, 0x44, 0x6f, 0x31, 0xd5,
0x94, 0x76, 0xa9, 0x53, 0xdb, 0x7e, 0x6a, 0xfe, 0xf5, 0xff, 0x6c, 0x66, 0xdd, 0x1f, 0x4c, 0xc3,
0x09, 0xee, 0xb5, 0x2f, 0x52, 0xbd, 0x70, 0x9d, 0xea, 0x10, 0xdd, 0x50, 0xf2, 0xcd, 0x2f, 0x3a,
0x5c, 0x12, 0x64, 0xdf, 0x04, 0xcc, 0x38, 0xaf, 0xae, 0x70, 0x0e, 0x57, 0x38, 0xaf, 0x6d, 0xe2,
0xfc, 0x7b, 0x09, 0xd6, 0xf7, 0x66, 0x01, 0xf2, 0x3d, 0xe7, 0x00, 0xe3, 0x97, 0xc3, 0xf9, 0x31,
0xac, 0x71, 0xce, 0x99, 0x17, 0x0e, 0x1d, 0x14, 0xde, 0x83, 0x75, 0x2e, 0x99, 0x81, 0x17, 0xbe,
0x40, 0xe1, 0x22, 0xd6, 0x39, 0xc6, 0x22, 0x96, 0x74, 0xaf, 0x58, 0x07, 0x18, 0xf3, 0x58, 0xb9,
0x84, 0xca, 0x77, 0x4b, 0xa8, 0xb2, 0x2e, 0x21, 0xf9, 0xe1, 0x24, 0xa4, 0x6c, 0x90, 0x50, 0xf5,
0x7f, 0x91, 0x10, 0x5c, 0x91, 0x50, 0x6d, 0x45, 0x42, 0xf5, 0x4d, 0x12, 0x32, 0x60, 0x73, 0x3f,
0x61, 0x38, 0xa0, 0x1e, 0x09, 0xde, 0x0d, 0xc5, 0xaa, 0x59, 0xae, 0x82, 0x7c, 0x20, 0x7f, 0x0d,
0xe0, 0x93, 0x95, 0x15, 0x61, 0x63, 0x1a, 0x92, 0x80, 0x8a, 0x42, 0xc5, 0x94, 0x07, 0xd9, 0x10,
0x17, 0x83, 0xfd, 0x4d, 0x28, 0x4d, 0x88, 0x4b, 0xb5, 0xa2, 0x28, 0xf2, 0xc9, 0x7a, 0x91, 0x7d,
0xe2, 0xda, 0xc2, 0x45, 0x7d, 0x0c, 0x4b, 0x11, 0x66, 0x42, 0x33, 0x75, 0x9b, 0x1f, 0xd5, 0x06,
0x54, 0x62, 0x7f, 0x88, 0xa3, 0x88, 0x44, 0xf9, 0xd4, 0x95, 0x63, 0x7f, 0x9f, 0x9b, 0x1c, 0xe2,
0xe2, 0x98, 0x52, 0x3c, 0xca, 0x58, 0xb5, 0x65, 0x17, 0xd1, 0xf7, 0x29, 0x1e, 0x65, 0x69, 0x6e,
0x7f, 0x0a, 0x60, 0xe9, 0x84, 0xba, 0xea, 0xc7, 0x10, 0xde, 0xda, 0x66, 0xfa, 0x7a, 0x02, 0x2b,
0xb5, 0x34, 0xdf, 0xf8, 0x1b, 0x87, 0x45, 0xb1, 0xc6, 0x6b, 0x9f, 0xfc, 0xf8, 0xdb, 0x97, 0x45,
0xdd, 0x78, 0x6a, 0xad, 0xaf, 0xd3, 0xdc, 0x7b, 0xc8, 0x92, 0xde, 0xf3, 0x8b, 0x79, 0x0b, 0x5c,
0xce, 0x5b, 0xe0, 0xd7, 0x79, 0x0b, 0x7c, 0x71, 0xd5, 0x2a, 0x5c, 0x5e, 0xb5, 0x0a, 0x3f, 0x5d,
0xb5, 0x0a, 0x1f, 0xdc, 0xd6, 0x13, 0x8e, 0xb9, 0x9c, 0x96, 0x81, 0x12, 0x11, 0x4a, 0x68, 0xea,
0xac, 0x22, 0x56, 0xed, 0xdb, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x31, 0x9d, 0x29, 0x4e,
0x08, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
+11 -8
View File
@@ -5,7 +5,8 @@ import (
"fmt"
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkmath "cosmossdk.io/math"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
@@ -55,14 +56,14 @@ func (args *TransactionArgs) String() string {
// This assumes that setTxDefaults has been called.
func (args *TransactionArgs) ToTransaction() *MsgEthereumTx {
var (
chainID, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas sdk.Int
chainID, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas sdkmath.Int
gas, nonce uint64
from, to string
)
// Set sender address or use zero address if none specified.
if args.ChainID != nil {
chainID = sdk.NewIntFromBigInt(args.ChainID.ToInt())
chainID = sdkmath.NewIntFromBigInt(args.ChainID.ToInt())
}
if args.Nonce != nil {
@@ -74,19 +75,19 @@ func (args *TransactionArgs) ToTransaction() *MsgEthereumTx {
}
if args.GasPrice != nil {
gasPrice = sdk.NewIntFromBigInt(args.GasPrice.ToInt())
gasPrice = sdkmath.NewIntFromBigInt(args.GasPrice.ToInt())
}
if args.MaxFeePerGas != nil {
maxFeePerGas = sdk.NewIntFromBigInt(args.MaxFeePerGas.ToInt())
maxFeePerGas = sdkmath.NewIntFromBigInt(args.MaxFeePerGas.ToInt())
}
if args.MaxPriorityFeePerGas != nil {
maxPriorityFeePerGas = sdk.NewIntFromBigInt(args.MaxPriorityFeePerGas.ToInt())
maxPriorityFeePerGas = sdkmath.NewIntFromBigInt(args.MaxPriorityFeePerGas.ToInt())
}
if args.Value != nil {
value = sdk.NewIntFromBigInt(args.Value.ToInt())
value = sdkmath.NewIntFromBigInt(args.Value.ToInt())
}
if args.To != nil {
@@ -143,10 +144,12 @@ func (args *TransactionArgs) ToTransaction() *MsgEthereumTx {
from = args.From.Hex()
}
return &MsgEthereumTx{
msg := MsgEthereumTx{
Data: any,
From: from,
}
msg.Hash = msg.AsTransaction().Hash().Hex()
return &msg
}
// ToMessage converts the arguments to the Message type used by the core evm.
+288
View File
@@ -0,0 +1,288 @@
package types
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
//"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
func (suite *TxDataTestSuite) TestTxArgsString() {
testCases := []struct {
name string
txArgs TransactionArgs
expectedString string
}{
{
"empty tx args",
TransactionArgs{},
"TransactionArgs{From:<nil>, To:<nil>, Gas:<nil>, Nonce:<nil>, Data:<nil>, Input:<nil>, AccessList:<nil>}",
},
{
"tx args with fields",
TransactionArgs{
From: &suite.addr,
To: &suite.addr,
Gas: &suite.hexUint64,
Nonce: &suite.hexUint64,
Input: &suite.hexInputBytes,
Data: &suite.hexDataBytes,
AccessList: &ethtypes.AccessList{},
},
fmt.Sprintf("TransactionArgs{From:%v, To:%v, Gas:%v, Nonce:%v, Data:%v, Input:%v, AccessList:%v}",
&suite.addr,
&suite.addr,
&suite.hexUint64,
&suite.hexUint64,
&suite.hexDataBytes,
&suite.hexInputBytes,
&ethtypes.AccessList{}),
},
}
for _, tc := range testCases {
outputString := tc.txArgs.String()
suite.Require().Equal(outputString, tc.expectedString)
}
}
func (suite *TxDataTestSuite) TestConvertTxArgsEthTx() {
testCases := []struct {
name string
txArgs TransactionArgs
}{
{
"empty tx args",
TransactionArgs{},
},
{
"no nil args",
TransactionArgs{
From: &suite.addr,
To: &suite.addr,
Gas: &suite.hexUint64,
GasPrice: &suite.hexBigInt,
MaxFeePerGas: &suite.hexBigInt,
MaxPriorityFeePerGas: &suite.hexBigInt,
Value: &suite.hexBigInt,
Nonce: &suite.hexUint64,
Data: &suite.hexDataBytes,
Input: &suite.hexInputBytes,
AccessList: &ethtypes.AccessList{{Address: suite.addr, StorageKeys: []common.Hash{{0}}}},
ChainID: &suite.hexBigInt,
},
},
{
"max fee per gas nil, but access list not nil",
TransactionArgs{
From: &suite.addr,
To: &suite.addr,
Gas: &suite.hexUint64,
GasPrice: &suite.hexBigInt,
MaxFeePerGas: nil,
MaxPriorityFeePerGas: &suite.hexBigInt,
Value: &suite.hexBigInt,
Nonce: &suite.hexUint64,
Data: &suite.hexDataBytes,
Input: &suite.hexInputBytes,
AccessList: &ethtypes.AccessList{{Address: suite.addr, StorageKeys: []common.Hash{{0}}}},
ChainID: &suite.hexBigInt,
},
},
}
for _, tc := range testCases {
res := tc.txArgs.ToTransaction()
suite.Require().NotNil(res)
}
}
func (suite *TxDataTestSuite) TestToMessageEVM() {
testCases := []struct {
name string
txArgs TransactionArgs
globalGasCap uint64
baseFee *big.Int
expError bool
}{
{
"empty tx args",
TransactionArgs{},
uint64(0),
nil,
false,
},
{
"specify gasPrice and (maxFeePerGas or maxPriorityFeePerGas)",
TransactionArgs{
From: &suite.addr,
To: &suite.addr,
Gas: &suite.hexUint64,
GasPrice: &suite.hexBigInt,
MaxFeePerGas: &suite.hexBigInt,
MaxPriorityFeePerGas: &suite.hexBigInt,
Value: &suite.hexBigInt,
Nonce: &suite.hexUint64,
Data: &suite.hexDataBytes,
Input: &suite.hexInputBytes,
AccessList: &ethtypes.AccessList{{Address: suite.addr, StorageKeys: []common.Hash{{0}}}},
ChainID: &suite.hexBigInt,
},
uint64(0),
nil,
true,
},
{
"non-1559 execution, zero gas cap",
TransactionArgs{
From: &suite.addr,
To: &suite.addr,
Gas: &suite.hexUint64,
GasPrice: &suite.hexBigInt,
MaxFeePerGas: nil,
MaxPriorityFeePerGas: nil,
Value: &suite.hexBigInt,
Nonce: &suite.hexUint64,
Data: &suite.hexDataBytes,
Input: &suite.hexInputBytes,
AccessList: &ethtypes.AccessList{{Address: suite.addr, StorageKeys: []common.Hash{{0}}}},
ChainID: &suite.hexBigInt,
},
uint64(0),
nil,
false,
},
{
"non-1559 execution, nonzero gas cap",
TransactionArgs{
From: &suite.addr,
To: &suite.addr,
Gas: &suite.hexUint64,
GasPrice: &suite.hexBigInt,
MaxFeePerGas: nil,
MaxPriorityFeePerGas: nil,
Value: &suite.hexBigInt,
Nonce: &suite.hexUint64,
Data: &suite.hexDataBytes,
Input: &suite.hexInputBytes,
AccessList: &ethtypes.AccessList{{Address: suite.addr, StorageKeys: []common.Hash{{0}}}},
ChainID: &suite.hexBigInt,
},
uint64(1),
nil,
false,
},
{
"1559-type execution, nil gas price",
TransactionArgs{
From: &suite.addr,
To: &suite.addr,
Gas: &suite.hexUint64,
GasPrice: nil,
MaxFeePerGas: &suite.hexBigInt,
MaxPriorityFeePerGas: &suite.hexBigInt,
Value: &suite.hexBigInt,
Nonce: &suite.hexUint64,
Data: &suite.hexDataBytes,
Input: &suite.hexInputBytes,
AccessList: &ethtypes.AccessList{{Address: suite.addr, StorageKeys: []common.Hash{{0}}}},
ChainID: &suite.hexBigInt,
},
uint64(1),
suite.bigInt,
false,
},
{
"1559-type execution, non-nil gas price",
TransactionArgs{
From: &suite.addr,
To: &suite.addr,
Gas: &suite.hexUint64,
GasPrice: &suite.hexBigInt,
MaxFeePerGas: nil,
MaxPriorityFeePerGas: nil,
Value: &suite.hexBigInt,
Nonce: &suite.hexUint64,
Data: &suite.hexDataBytes,
Input: &suite.hexInputBytes,
AccessList: &ethtypes.AccessList{{Address: suite.addr, StorageKeys: []common.Hash{{0}}}},
ChainID: &suite.hexBigInt,
},
uint64(1),
suite.bigInt,
false,
},
}
for _, tc := range testCases {
res, err := tc.txArgs.ToMessage(tc.globalGasCap, tc.baseFee)
if tc.expError {
suite.Require().NotNil(err)
} else {
suite.Require().Nil(err)
suite.Require().NotNil(res)
}
}
}
func (suite *TxDataTestSuite) TestGetFrom() {
testCases := []struct {
name string
txArgs TransactionArgs
expAddress common.Address
}{
{
"empty from field",
TransactionArgs{},
common.Address{},
},
{
"non-empty from field",
TransactionArgs{
From: &suite.addr,
},
suite.addr,
},
}
for _, tc := range testCases {
retrievedAddress := tc.txArgs.GetFrom()
suite.Require().Equal(retrievedAddress, tc.expAddress)
}
}
func (suite *TxDataTestSuite) TestGetData() {
testCases := []struct {
name string
txArgs TransactionArgs
expectedOutput []byte
}{
{
"empty input and data fields",
TransactionArgs{
Data: nil,
Input: nil,
},
nil,
},
{
"empty input field, non-empty data field",
TransactionArgs{
Data: &suite.hexDataBytes,
Input: nil,
},
[]byte("data"),
},
{
"non-empty input and data fields",
TransactionArgs{
Data: &suite.hexDataBytes,
Input: &suite.hexInputBytes,
},
[]byte("input"),
},
}
for _, tc := range testCases {
retrievedData := tc.txArgs.GetData()
suite.Require().Equal(retrievedData, tc.expectedOutput)
}
}
+7 -3
View File
@@ -41,11 +41,14 @@ type TxData interface {
Fee() *big.Int
Cost() *big.Int
// effective fee according to current base fee
// effective gasPrice/fee/cost according to current base fee
EffectiveGasPrice(baseFee *big.Int) *big.Int
EffectiveFee(baseFee *big.Int) *big.Int
EffectiveCost(baseFee *big.Int) *big.Int
}
// NOTE: All non-protected transactions (i.e non EIP155 signed) will fail if the
// AllowUnprotectedTxs parameter is disabled.
func NewTxDataFromTx(tx *ethtypes.Transaction) (TxData, error) {
var txData TxData
var err error
@@ -68,8 +71,9 @@ func NewTxDataFromTx(tx *ethtypes.Transaction) (TxData, error) {
//
// CONTRACT: v value is either:
//
// - {0,1} + CHAIN_ID * 2 + 35, if EIP155 is used
// - {0,1} + 27, otherwise
// - {0,1} + CHAIN_ID * 2 + 35, if EIP155 is used
// - {0,1} + 27, otherwise
//
// Ref: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
func DeriveChainID(v *big.Int) *big.Int {
if v == nil || v.Sign() < 1 {
+2 -3
View File
@@ -4,13 +4,12 @@ import (
"math/big"
"testing"
sdkmath "cosmossdk.io/math"
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func TestTxData_chainID(t *testing.T) {
chainID := sdk.NewInt(1)
chainID := sdkmath.NewInt(1)
testCases := []struct {
msg string
+31 -27
View File
@@ -6,39 +6,38 @@ import (
"github.com/gogo/protobuf/proto"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
)
const maxBitLen = 256
// DefaultPriorityReduction is the default amount of price values required for 1 unit of priority.
// Because priority is `int64` while price is `big.Int`, it's necessary to scale down the range to keep it more pratical.
// The default value is the same as the `sdk.DefaultPowerReduction`.
var DefaultPriorityReduction = sdk.DefaultPowerReduction
var EmptyCodeHash = crypto.Keccak256(nil)
// DecodeTxResponse decodes an protobuf-encoded byte slice into TxResponse
func DecodeTxResponse(in []byte, cdc codec.Codec) (*MsgEthereumTxResponse, error) {
func DecodeTxResponse(in []byte) (*MsgEthereumTxResponse, error) {
var txMsgData sdk.TxMsgData
if err := txMsgData.Unmarshal(in); err != nil {
if err := proto.Unmarshal(in, &txMsgData); err != nil {
return nil, err
}
responses := txMsgData.GetMsgResponses()
if len(responses) == 0 {
return nil, nil
if len(txMsgData.MsgResponses) == 0 {
return &MsgEthereumTxResponse{}, nil
}
if err := cdc.UnpackAny(responses[0], new(TxResponse)); err != nil {
return nil, fmt.Errorf("failed to unmarshal tx response message: %w", err)
var res MsgEthereumTxResponse
if err := proto.Unmarshal(txMsgData.MsgResponses[0].Value, &res); err != nil {
return nil, sdkerrors.Wrap(err, "failed to unmarshal tx response message data")
}
msgval := responses[0].GetCachedValue()
res, ok := msgval.(*MsgEthereumTxResponse)
if !ok {
return nil, fmt.Errorf("tx response message has invalid type: %T", msgval)
}
return res, nil
return &res, nil
}
// EncodeTransactionLogs encodes TransactionLogs slice into a protobuf-encoded byte slice.
@@ -46,6 +45,16 @@ func EncodeTransactionLogs(res *TransactionLogs) ([]byte, error) {
return proto.Marshal(res)
}
// DecodeTransactionLogs decodes an protobuf-encoded byte slice into TransactionLogs
func DecodeTransactionLogs(data []byte) (TransactionLogs, error) {
var logs TransactionLogs
err := proto.Unmarshal(data, &logs)
if err != nil {
return TransactionLogs{}, err
}
return logs, nil
}
// UnwrapEthereumMsg extract MsgEthereumTx from wrapping sdk.Tx
func UnwrapEthereumMsg(tx *sdk.Tx, ethHash common.Hash) (*MsgEthereumTx, error) {
if tx == nil {
@@ -57,7 +66,9 @@ func UnwrapEthereumMsg(tx *sdk.Tx, ethHash common.Hash) (*MsgEthereumTx, error)
if !ok {
return nil, fmt.Errorf("invalid tx type: %T", tx)
}
if ethMsg.AsTransaction().Hash() == ethHash {
txHash := ethMsg.AsTransaction().Hash()
ethMsg.Hash = txHash.Hex()
if txHash == ethHash {
return ethMsg, nil
}
}
@@ -85,15 +96,8 @@ func BinSearch(lo, hi uint64, executable func(uint64) (bool, *MsgEthereumTxRespo
return hi, nil
}
// SafeNewIntFromBigInt constructs Int from big.Int, return error if more than 256bits
func SafeNewIntFromBigInt(i *big.Int) (sdk.Int, error) {
if !IsValidInt256(i) {
return sdk.NewInt(0), fmt.Errorf("big int out of bound: %s", i)
}
return sdk.NewIntFromBigInt(i), nil
}
// IsValidInt256 check the bound of 256 bit number
func IsValidInt256(i *big.Int) bool {
return i == nil || i.BitLen() <= maxBitLen
// EffectiveGasPrice compute the effective gas price based on eip-1159 rules
// `effectiveGasPrice = min(baseFee + tipCap, feeCap)`
func EffectiveGasPrice(baseFee *big.Int, feeCap *big.Int, tipCap *big.Int) *big.Int {
return math.BigMin(new(big.Int).Add(tipCap, baseFee), feeCap)
}
+44 -24
View File
@@ -5,33 +5,26 @@ import (
"math/big"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/cerc-io/laconicd/app"
"github.com/cerc-io/laconicd/encoding"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
"github.com/cosmos/cosmos-sdk/client"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
proto "github.com/gogo/protobuf/proto"
"github.com/cerc-io/laconicd/tests"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common"
)
var testCodec codec.Codec
func init() {
registry := codectypes.NewInterfaceRegistry()
evmtypes.RegisterInterfaces(registry)
testCodec = codec.NewProtoCodec(registry)
}
func TestEvmDataEncoding(t *testing.T) {
ret := []byte{0x5, 0x8}
resp := &evmtypes.MsgEthereumTxResponse{
data := &evmtypes.MsgEthereumTxResponse{
Hash: common.BytesToHash([]byte("hash")).String(),
Logs: []*evmtypes.Log{{
Data: []byte{1, 2, 3, 4},
@@ -40,20 +33,19 @@ func TestEvmDataEncoding(t *testing.T) {
Ret: ret,
}
any, err := codectypes.NewAnyWithValue(resp)
require.NoError(t, err)
any := codectypes.UnsafePackAny(data)
txData := &sdk.TxMsgData{
MsgResponses: []*codectypes.Any{any},
}
txDataBz, err := txData.Marshal()
txDataBz, err := proto.Marshal(txData)
require.NoError(t, err)
decoded, err := evmtypes.DecodeTxResponse(txDataBz, testCodec)
res, err := evmtypes.DecodeTxResponse(txDataBz)
require.NoError(t, err)
require.NotNil(t, decoded)
require.Equal(t, resp.Logs, decoded.Logs)
require.Equal(t, ret, decoded.Ret)
require.NotNil(t, res)
require.Equal(t, data.Logs, res.Logs)
require.Equal(t, ret, res.Ret)
}
func TestUnwrapEthererumMsg(t *testing.T) {
@@ -94,3 +86,31 @@ func TestBinSearch(t *testing.T) {
require.Error(t, err)
require.Equal(t, gas, uint64(0))
}
func TestTransactionLogsEncodeDecode(t *testing.T) {
addr := tests.GenerateAddress().String()
txLogs := evmtypes.TransactionLogs{
Hash: common.BytesToHash([]byte("tx_hash")).String(),
Logs: []*evmtypes.Log{
{
Address: addr,
Topics: []string{common.BytesToHash([]byte("topic")).String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: common.BytesToHash([]byte("tx_hash")).String(),
TxIndex: 1,
BlockHash: common.BytesToHash([]byte("block_hash")).String(),
Index: 1,
Removed: false,
},
},
}
txLogsEncoded, encodeErr := evmtypes.EncodeTransactionLogs(&txLogs)
require.Nil(t, encodeErr)
txLogsEncodedDecoded, decodeErr := evmtypes.DecodeTransactionLogs(txLogsEncoded)
require.Nil(t, decodeErr)
require.Equal(t, txLogs, txLogsEncodedDecoded)
}
+79
View File
@@ -0,0 +1,79 @@
package geth
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
evm "github.com/cerc-io/laconicd/x/evm/vm"
)
var (
_ evm.EVM = (*EVM)(nil)
_ evm.Constructor = NewEVM
)
// EVM is the wrapper for the go-ethereum EVM.
type EVM struct {
*vm.EVM
}
// NewEVM defines the constructor function for the go-ethereum (geth) EVM. It uses
// the default precompiled contracts and the EVM concrete implementation from
// geth.
func NewEVM(
blockCtx vm.BlockContext,
txCtx vm.TxContext,
stateDB vm.StateDB,
chainConfig *params.ChainConfig,
config vm.Config,
_ evm.PrecompiledContracts, // unused
) evm.EVM {
return &EVM{
EVM: vm.NewEVM(blockCtx, txCtx, stateDB, chainConfig, config),
}
}
// Context returns the EVM's Block Context
func (e EVM) Context() vm.BlockContext {
return e.EVM.Context
}
// TxContext returns the EVM's Tx Context
func (e EVM) TxContext() vm.TxContext {
return e.EVM.TxContext
}
// Config returns the configuration options for the EVM.
func (e EVM) Config() vm.Config {
return e.EVM.Config
}
// Precompile returns the precompiled contract associated with the given address
// and the current chain configuration. If the contract cannot be found it returns
// nil.
func (e EVM) Precompile(addr common.Address) (p vm.PrecompiledContract, found bool) {
precompiles := GetPrecompiles(e.ChainConfig(), e.EVM.Context.BlockNumber)
p, found = precompiles[addr]
return p, found
}
// ActivePrecompiles returns a list of all the active precompiled contract addresses
// for the current chain configuration.
func (EVM) ActivePrecompiles(rules params.Rules) []common.Address {
return vm.ActivePrecompiles(rules)
}
// RunPrecompiledContract runs a stateless precompiled contract and ignores the address and
// value arguments. It uses the RunPrecompiledContract function from the geth vm package.
func (EVM) RunPrecompiledContract(
p evm.StatefulPrecompiledContract,
_ common.Address, // address arg is unused
input []byte,
suppliedGas uint64,
_ *big.Int, // value arg is unused
) (ret []byte, remainingGas uint64, err error) {
return vm.RunPrecompiledContract(p, input, suppliedGas)
}
+27
View File
@@ -0,0 +1,27 @@
package geth
import (
"math/big"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
evm "github.com/cerc-io/laconicd/x/evm/vm"
)
// GetPrecompiles returns all the precompiled contracts defined given the
// current chain configuration and block height.
func GetPrecompiles(cfg *params.ChainConfig, blockNumber *big.Int) evm.PrecompiledContracts {
var precompiles evm.PrecompiledContracts
switch {
case cfg.IsBerlin(blockNumber):
precompiles = vm.PrecompiledContractsBerlin
case cfg.IsIstanbul(blockNumber):
precompiles = vm.PrecompiledContractsIstanbul
case cfg.IsByzantium(blockNumber):
precompiles = vm.PrecompiledContractsByzantium
default:
precompiles = vm.PrecompiledContractsHomestead
}
return precompiles
}
+66
View File
@@ -0,0 +1,66 @@
package vm
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)
// PrecompiledContracts defines a map of address -> precompiled contract
type PrecompiledContracts map[common.Address]vm.PrecompiledContract
type StatefulPrecompiledContract interface {
vm.PrecompiledContract
RunStateful(evm EVM, addr common.Address, input []byte, value *big.Int) (ret []byte, err error)
}
// EVM defines the interface for the Ethereum Virtual Machine used by the EVM module.
type EVM interface {
Config() vm.Config
Context() vm.BlockContext
TxContext() vm.TxContext
Reset(txCtx vm.TxContext, statedb vm.StateDB)
Cancel()
Cancelled() bool //nolint
Interpreter() *vm.EVMInterpreter
Call(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error)
CallCode(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error)
DelegateCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error)
StaticCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error)
Create(caller vm.ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error)
Create2(
caller vm.ContractRef,
code []byte,
gas uint64,
endowment *big.Int,
salt *uint256.Int) (
ret []byte, contractAddr common.Address, leftOverGas uint64, err error,
)
ChainConfig() *params.ChainConfig
ActivePrecompiles(rules params.Rules) []common.Address
Precompile(addr common.Address) (vm.PrecompiledContract, bool)
RunPrecompiledContract(
p StatefulPrecompiledContract,
addr common.Address,
input []byte,
suppliedGas uint64,
value *big.Int) (
ret []byte, remainingGas uint64, err error,
)
}
// Constructor defines the function used to instantiate the EVM on
// each state transition.
type Constructor func(
blockCtx vm.BlockContext,
txCtx vm.TxContext,
stateDB vm.StateDB,
chainConfig *params.ChainConfig,
config vm.Config,
customPrecompiles PrecompiledContracts,
) EVM