forked from cerc-io/laconicd-deprecated
update fork
This commit is contained in:
@@ -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)
|
||||
@@ -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"
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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
@@ -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 := ðermint.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 = ðermint.EthAccount{
|
||||
acc := ðermint.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")
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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), ðtypes.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), ðtypes.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), ðtypes.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), ðtypes.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
@@ -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
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, ¶ms)
|
||||
// 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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 := ðtypes.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 := ðtypes.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())
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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, ¶ms)
|
||||
|
||||
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, ¶mstore)
|
||||
require.NoError(t, err)
|
||||
|
||||
var result bool
|
||||
paramstore.Get(ctx, types.ParamStoreKeyAllowUnprotectedTxs, &result)
|
||||
require.Equal(t, types.DefaultAllowUnprotectedTxs, result)
|
||||
}
|
||||
@@ -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 ¶ms.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
|
||||
}
|
||||
Generated
+3781
File diff suppressed because it is too large
Load Diff
@@ -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))
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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, ¶ms)
|
||||
|
||||
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, ¶mstore)
|
||||
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)
|
||||
})
|
||||
}
|
||||
@@ -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 ¶ms.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
|
||||
}
|
||||
Generated
+3812
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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, "", " ")
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -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 account’s 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
@@ -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
@@ -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`:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -77,4 +77,3 @@ By default, all block configuration fields but `ConstantinopleBlock`, are enable
|
||||
| MuirGlacierBlock | 0 |
|
||||
| BerlinBlock | 0 |
|
||||
| LondonBlock | 0 |
|
||||
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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(ðtypes.AccessListTx{ // TODO: change to DynamicFeeTx on Geth
|
||||
false,
|
||||
ethtypes.NewTx(ðtypes.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(ðtypes.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(ðtypes.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(ðtypes.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 := ðtypes.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")
|
||||
|
||||
@@ -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
|
||||
|
||||
Generated
+209
-106
@@ -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
|
||||
|
||||
Generated
+20
-21
@@ -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) {
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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: ðtypes.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: ðtypes.AccessList{}, chainID: &hundredInt, expectPass: true},
|
||||
{msg: "negative amount - AccessListTx", to: suite.to.Hex(), amount: &minusOneInt, gasPrice: &hundredInt, accessList: ðtypes.AccessList{}, chainID: nil, expectPass: false},
|
||||
{msg: "nil gas price - AccessListTx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: nil, accessList: ðtypes.AccessList{}, chainID: &hundredInt, expectPass: false},
|
||||
{msg: "negative gas price - AccessListTx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &minusOneInt, accessList: ðtypes.AccessList{}, chainID: nil, expectPass: false},
|
||||
{msg: "zero gas price - AccessListTx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &zeroInt, accessList: ðtypes.AccessList{}, chainID: &hundredInt, expectPass: true},
|
||||
{msg: "invalid from address - AccessListTx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &zeroInt, from: invalidFromAddress, accessList: ðtypes.AccessList{}, chainID: &hundredInt, expectPass: false},
|
||||
{msg: "chain ID not set on AccessListTx", to: suite.to.Hex(), amount: &hundredInt, gasPrice: &zeroInt, accessList: ðtypes.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: ðtypes.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: ðtypes.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: ðtypes.AccessList{},
|
||||
chainID: hundredInt,
|
||||
expectPass: true,
|
||||
},
|
||||
{
|
||||
msg: "negative amount - AccessListTx",
|
||||
to: suite.to.Hex(),
|
||||
amount: minusOneInt,
|
||||
gasLimit: 1000,
|
||||
gasPrice: hundredInt,
|
||||
gasFeeCap: nil,
|
||||
gasTipCap: nil,
|
||||
accessList: ðtypes.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: ðtypes.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: ðtypes.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: ðtypes.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: ðtypes.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: ðtypes.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: ðtypes.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: ðtypes.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, ðtypes.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, ðtypes.AccessList{}),
|
||||
ethtypes.NewEIP2930Signer(suite.chainID),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"get effective fee - pass",
|
||||
types.NewTx(suite.chainID, 0, &suite.to, nil, 50, suite.hundredBigInt, nil, nil, nil, ðtypes.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, ðtypes.AccessList{}),
|
||||
ethtypes.NewEIP2930Signer(suite.chainID),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"get gas - pass",
|
||||
types.NewTx(suite.chainID, 0, &suite.to, nil, 50, suite.hundredBigInt, nil, nil, nil, ðtypes.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, ðtypes.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(ðtypes.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(ðtypes.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(ðtypes.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(ðtypes.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(ðtypes.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(ðtypes.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
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Generated
+422
-119
@@ -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
|
||||
|
||||
Generated
+62
@@ -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
@@ -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) {}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
Generated
+58
-56
@@ -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
@@ -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.
|
||||
|
||||
@@ -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: ðtypes.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,
|
||||
ðtypes.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: ðtypes.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: ðtypes.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: ðtypes.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: ðtypes.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: ðtypes.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: ðtypes.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: ðtypes.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)
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user