Sync from fork #74
@ -64,6 +64,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
* (cli) [#1360](https://github.com/evmos/ethermint/pull/1360) Introduce a new `grpc-only` flag, such that when enabled, will start the node in a query-only mode. Note, gRPC MUST be enabled with this flag.
|
||||
* (rpc) [#1378](https://github.com/evmos/ethermint/pull/1378) Add support for EVM RPC metrics
|
||||
* (ante) [#1390](https://github.com/evmos/ethermint/pull/1390) Added multisig tx support.
|
||||
* (test) [#1396](https://github.com/evmos/ethermint/pull/1396) Increase test coverage for the EVM module `keeper`
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
|
18
x/evm/keeper/abci_test.go
Normal file
18
x/evm/keeper/abci_test.go
Normal file
@ -0,0 +1,18 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||
"github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
func (suite *KeeperTestSuite) TestEndBlock() {
|
||||
em := suite.ctx.EventManager()
|
||||
suite.Require().Equal(0, len(em.Events()))
|
||||
|
||||
res := suite.app.EvmKeeper.EndBlock(suite.ctx, types.RequestEndBlock{})
|
||||
suite.Require().Equal([]types.ValidatorUpdate{}, res)
|
||||
|
||||
// should emit 1 EventTypeBlockBloom event on EndBlock
|
||||
suite.Require().Equal(1, len(em.Events()))
|
||||
suite.Require().Equal(evmtypes.EventTypeBlockBloom, em.Events()[0].Type)
|
||||
}
|
@ -13,11 +13,11 @@ import (
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
ethlogger "github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||
ethparams "github.com/ethereum/go-ethereum/params"
|
||||
"github.com/evmos/ethermint/tests"
|
||||
"github.com/evmos/ethermint/x/evm/statedb"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/evmos/ethermint/crypto/ethsecp256k1"
|
||||
"github.com/evmos/ethermint/server/config"
|
||||
ethermint "github.com/evmos/ethermint/types"
|
||||
"github.com/evmos/ethermint/x/evm/types"
|
||||
@ -491,9 +491,11 @@ func (suite *KeeperTestSuite) TestQueryValidatorAccount() {
|
||||
|
||||
func (suite *KeeperTestSuite) TestEstimateGas() {
|
||||
gasHelper := hexutil.Uint64(20000)
|
||||
higherGas := hexutil.Uint64(25000)
|
||||
hexBigInt := hexutil.Big(*big.NewInt(1))
|
||||
|
||||
var (
|
||||
args types.TransactionArgs
|
||||
args interface{}
|
||||
gasCap uint64
|
||||
)
|
||||
testCases := []struct {
|
||||
@ -504,78 +506,223 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
|
||||
enableFeemarket bool
|
||||
}{
|
||||
// should success, because transfer value is zero
|
||||
{"default args", func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}}
|
||||
}, true, 21000, false},
|
||||
{
|
||||
"default args - special case for ErrIntrinsicGas on contract creation, raise gas limit",
|
||||
func() {
|
||||
args = types.TransactionArgs{}
|
||||
},
|
||||
true,
|
||||
ethparams.TxGasContractCreation,
|
||||
false,
|
||||
},
|
||||
// should success, because transfer value is zero
|
||||
{
|
||||
"default args with 'to' address",
|
||||
func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}}
|
||||
},
|
||||
true,
|
||||
ethparams.TxGas,
|
||||
false,
|
||||
},
|
||||
// should fail, because the default From address(zero address) don't have fund
|
||||
{"not enough balance", func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}, Value: (*hexutil.Big)(big.NewInt(100))}
|
||||
}, false, 0, false},
|
||||
{
|
||||
"not enough balance",
|
||||
func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}, Value: (*hexutil.Big)(big.NewInt(100))}
|
||||
},
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
},
|
||||
// should success, enough balance now
|
||||
{"enough balance", func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}, From: &suite.address, Value: (*hexutil.Big)(big.NewInt(100))}
|
||||
}, false, 0, false},
|
||||
{
|
||||
"enough balance",
|
||||
func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}, From: &suite.address, Value: (*hexutil.Big)(big.NewInt(100))}
|
||||
}, false, 0, false},
|
||||
// should success, because gas limit lower than 21000 is ignored
|
||||
{"gas exceed allowance", func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}, Gas: &gasHelper}
|
||||
}, true, 21000, false},
|
||||
{
|
||||
"gas exceed allowance",
|
||||
func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}, Gas: &gasHelper}
|
||||
},
|
||||
true,
|
||||
ethparams.TxGas,
|
||||
false,
|
||||
},
|
||||
// should fail, invalid gas cap
|
||||
{"gas exceed global allowance", func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}}
|
||||
gasCap = 20000
|
||||
}, false, 0, false},
|
||||
{
|
||||
"gas exceed global allowance",
|
||||
func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}}
|
||||
gasCap = 20000
|
||||
},
|
||||
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, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
|
||||
suite.Require().NoError(err)
|
||||
data := append(types.ERC20Contract.Bin, ctorArgs...)
|
||||
args = types.TransactionArgs{
|
||||
From: &suite.address,
|
||||
Data: (*hexutil.Bytes)(&data),
|
||||
}
|
||||
}, true, 1186778, false},
|
||||
{
|
||||
"contract deployment",
|
||||
func() {
|
||||
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{
|
||||
From: &suite.address,
|
||||
Data: (*hexutil.Bytes)(&data),
|
||||
}
|
||||
},
|
||||
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, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
|
||||
suite.Commit()
|
||||
transferData, err := types.ERC20Contract.ABI.Pack("transfer", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000))
|
||||
suite.Require().NoError(err)
|
||||
args = types.TransactionArgs{To: &contractAddr, From: &suite.address, Data: (*hexutil.Bytes)(&transferData)}
|
||||
}, true, 51880, false},
|
||||
|
||||
{
|
||||
"erc20 transfer",
|
||||
func() {
|
||||
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)
|
||||
args = types.TransactionArgs{To: &contractAddr, From: &suite.address, Data: (*hexutil.Bytes)(&transferData)}
|
||||
},
|
||||
true,
|
||||
51880,
|
||||
false,
|
||||
},
|
||||
// repeated tests with enableFeemarket
|
||||
{"default args w/ enableFeemarket", func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}}
|
||||
}, true, 21000, true},
|
||||
{"not enough balance w/ enableFeemarket", func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}, Value: (*hexutil.Big)(big.NewInt(100))}
|
||||
}, false, 0, true},
|
||||
{"enough balance w/ enableFeemarket", func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}, From: &suite.address, Value: (*hexutil.Big)(big.NewInt(100))}
|
||||
}, false, 0, true},
|
||||
{"gas exceed allowance w/ enableFeemarket", func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}, Gas: &gasHelper}
|
||||
}, true, 21000, true},
|
||||
{"gas exceed global allowance w/ enableFeemarket", func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}}
|
||||
gasCap = 20000
|
||||
}, false, 0, true},
|
||||
{"contract deployment w/ enableFeemarket", func() {
|
||||
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{
|
||||
From: &suite.address,
|
||||
Data: (*hexutil.Bytes)(&data),
|
||||
}
|
||||
}, true, 1186778, true},
|
||||
{"erc20 transfer w/ enableFeemarket", func() {
|
||||
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)
|
||||
args = types.TransactionArgs{To: &contractAddr, From: &suite.address, Data: (*hexutil.Bytes)(&transferData)}
|
||||
}, true, 51880, true},
|
||||
{
|
||||
"default args w/ enableFeemarket",
|
||||
func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}}
|
||||
},
|
||||
true,
|
||||
ethparams.TxGas,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"not enough balance w/ enableFeemarket",
|
||||
func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}, Value: (*hexutil.Big)(big.NewInt(100))}
|
||||
},
|
||||
false,
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"enough balance w/ enableFeemarket",
|
||||
func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}, From: &suite.address, Value: (*hexutil.Big)(big.NewInt(100))}
|
||||
},
|
||||
false,
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"gas exceed allowance w/ enableFeemarket",
|
||||
func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}, Gas: &gasHelper}
|
||||
},
|
||||
true,
|
||||
ethparams.TxGas,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"gas exceed global allowance w/ enableFeemarket",
|
||||
func() {
|
||||
args = types.TransactionArgs{To: &common.Address{}}
|
||||
gasCap = 20000
|
||||
},
|
||||
false,
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"contract deployment w/ enableFeemarket",
|
||||
func() {
|
||||
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{
|
||||
From: &suite.address,
|
||||
Data: (*hexutil.Bytes)(&data),
|
||||
}
|
||||
},
|
||||
true,
|
||||
1186778,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"erc20 transfer w/ enableFeemarket",
|
||||
func() {
|
||||
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)
|
||||
args = types.TransactionArgs{To: &contractAddr, From: &suite.address, Data: (*hexutil.Bytes)(&transferData)}
|
||||
},
|
||||
true,
|
||||
51880,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"contract creation but 'create' param disabled",
|
||||
func() {
|
||||
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{
|
||||
From: &suite.address,
|
||||
Data: (*hexutil.Bytes)(&data),
|
||||
}
|
||||
params := suite.app.EvmKeeper.GetParams(suite.ctx)
|
||||
params.EnableCreate = false
|
||||
suite.app.EvmKeeper.SetParams(suite.ctx, params)
|
||||
},
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"specified gas in args higher than ethparams.TxGas (21,000)",
|
||||
func() {
|
||||
args = types.TransactionArgs{
|
||||
To: &common.Address{},
|
||||
Gas: &higherGas,
|
||||
}
|
||||
},
|
||||
true,
|
||||
ethparams.TxGas,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"specified gas in args higher than request gasCap",
|
||||
func() {
|
||||
gasCap = 22_000
|
||||
args = types.TransactionArgs{
|
||||
To: &common.Address{},
|
||||
Gas: &higherGas,
|
||||
}
|
||||
},
|
||||
true,
|
||||
ethparams.TxGas,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid args - specified both gasPrice and maxFeePerGas",
|
||||
func() {
|
||||
args = types.TransactionArgs{
|
||||
To: &common.Address{},
|
||||
GasPrice: &hexBigInt,
|
||||
MaxFeePerGas: &hexBigInt,
|
||||
}
|
||||
},
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@ -702,6 +849,88 @@ func (suite *KeeperTestSuite) TestTraceTx() {
|
||||
traceResponse: "{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PUSH1\",\"gas\":",
|
||||
enableFeemarket: false,
|
||||
},
|
||||
{
|
||||
msg: "invalid trace config - Negative Limit",
|
||||
malleate: func() {
|
||||
traceConfig = &types.TraceConfig{
|
||||
DisableStack: true,
|
||||
DisableStorage: true,
|
||||
EnableMemory: false,
|
||||
Limit: -1,
|
||||
}
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
msg: "invalid trace config - Invalid Tracer",
|
||||
malleate: func() {
|
||||
traceConfig = &types.TraceConfig{
|
||||
DisableStack: true,
|
||||
DisableStorage: true,
|
||||
EnableMemory: false,
|
||||
Tracer: "invalid_tracer",
|
||||
}
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
msg: "invalid trace config - Invalid Timeout",
|
||||
malleate: func() {
|
||||
traceConfig = &types.TraceConfig{
|
||||
DisableStack: true,
|
||||
DisableStorage: true,
|
||||
EnableMemory: false,
|
||||
Timeout: "wrong_time",
|
||||
}
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
msg: "trace config - Execution Timeout",
|
||||
malleate: func() {
|
||||
traceConfig = &types.TraceConfig{
|
||||
DisableStack: true,
|
||||
DisableStorage: true,
|
||||
EnableMemory: false,
|
||||
Timeout: "0s",
|
||||
}
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
msg: "default tracer with contract creation tx as predecessor but 'create' param disabled",
|
||||
malleate: func() {
|
||||
traceConfig = nil
|
||||
|
||||
// increase nonce to avoid address collision
|
||||
vmdb := suite.StateDB()
|
||||
vmdb.SetNonce(suite.address, vmdb.GetNonce(suite.address)+1)
|
||||
suite.Require().NoError(vmdb.Commit())
|
||||
|
||||
chainID := suite.app.EvmKeeper.ChainID()
|
||||
nonce := suite.app.EvmKeeper.GetNonce(suite.ctx, suite.address)
|
||||
data := types.ERC20Contract.Bin
|
||||
contractTx := types.NewTxContract(
|
||||
chainID,
|
||||
nonce,
|
||||
nil, // amount
|
||||
ethparams.TxGasContractCreation, // gasLimit
|
||||
nil, // gasPrice
|
||||
nil, nil,
|
||||
data, // input
|
||||
nil, // accesses
|
||||
)
|
||||
|
||||
predecessors = append(predecessors, contractTx)
|
||||
suite.Commit()
|
||||
|
||||
params := suite.app.EvmKeeper.GetParams(suite.ctx)
|
||||
params.EnableCreate = false
|
||||
suite.app.EvmKeeper.SetParams(suite.ctx, params)
|
||||
},
|
||||
expPass: true,
|
||||
traceResponse: "{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PUSH1\",\"gas\":",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@ -722,7 +951,6 @@ func (suite *KeeperTestSuite) TestTraceTx() {
|
||||
Predecessors: predecessors,
|
||||
}
|
||||
res, err := suite.queryClient.TraceTx(sdk.WrapSDKContext(suite.ctx), &traceReq)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
@ -836,6 +1064,31 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
|
||||
traceResponse: "[{\"result\":{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PU",
|
||||
enableFeemarket: false,
|
||||
},
|
||||
{
|
||||
msg: "invalid trace config - Negative Limit",
|
||||
malleate: func() {
|
||||
traceConfig = &types.TraceConfig{
|
||||
DisableStack: true,
|
||||
DisableStorage: true,
|
||||
EnableMemory: false,
|
||||
Limit: -1,
|
||||
}
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
msg: "invalid trace config - Invalid Tracer",
|
||||
malleate: func() {
|
||||
traceConfig = &types.TraceConfig{
|
||||
DisableStack: true,
|
||||
DisableStorage: true,
|
||||
EnableMemory: false,
|
||||
Tracer: "invalid_tracer",
|
||||
}
|
||||
},
|
||||
expPass: true,
|
||||
traceResponse: "[]",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@ -877,10 +1130,7 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestNonceInQuery() {
|
||||
suite.SetupTest()
|
||||
priv, err := ethsecp256k1.GenerateKey()
|
||||
suite.Require().NoError(err)
|
||||
address := common.BytesToAddress(priv.PubKey().Address().Bytes())
|
||||
address := tests.GenerateAddress()
|
||||
suite.Require().Equal(uint64(0), suite.app.EvmKeeper.GetNonce(suite.ctx, address))
|
||||
supply := sdkmath.NewIntWithDecimal(1000, 18).BigInt()
|
||||
|
||||
@ -981,3 +1231,158 @@ func (suite *KeeperTestSuite) TestQueryBaseFee() {
|
||||
suite.enableFeemarket = false
|
||||
suite.enableLondonHF = true
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestEthCall() {
|
||||
var (
|
||||
req *types.EthCallRequest
|
||||
)
|
||||
|
||||
address := tests.GenerateAddress()
|
||||
suite.Require().Equal(uint64(0), suite.app.EvmKeeper.GetNonce(suite.ctx, address))
|
||||
supply := sdkmath.NewIntWithDecimal(1000, 18).BigInt()
|
||||
|
||||
hexBigInt := hexutil.Big(*big.NewInt(1))
|
||||
ctorArgs, err := types.ERC20Contract.ABI.Pack("", address, supply)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
data := append(types.ERC20Contract.Bin, ctorArgs...)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
malleate func()
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"invalid args",
|
||||
func() {
|
||||
req = &types.EthCallRequest{Args: []byte("invalid args"), GasCap: uint64(config.DefaultGasCap)}
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid args - specified both gasPrice and maxFeePerGas",
|
||||
func() {
|
||||
args, err := json.Marshal(&types.TransactionArgs{
|
||||
From: &address,
|
||||
Data: (*hexutil.Bytes)(&data),
|
||||
GasPrice: &hexBigInt,
|
||||
MaxFeePerGas: &hexBigInt,
|
||||
})
|
||||
|
||||
suite.Require().NoError(err)
|
||||
req = &types.EthCallRequest{Args: args, GasCap: uint64(config.DefaultGasCap)}
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"set param EnableCreate = false",
|
||||
func() {
|
||||
args, err := json.Marshal(&types.TransactionArgs{
|
||||
From: &address,
|
||||
Data: (*hexutil.Bytes)(&data),
|
||||
})
|
||||
|
||||
suite.Require().NoError(err)
|
||||
req = &types.EthCallRequest{Args: args, GasCap: uint64(config.DefaultGasCap)}
|
||||
|
||||
params := suite.app.EvmKeeper.GetParams(suite.ctx)
|
||||
params.EnableCreate = false
|
||||
suite.app.EvmKeeper.SetParams(suite.ctx, params)
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest()
|
||||
tc.malleate()
|
||||
|
||||
res, err := suite.queryClient.EthCall(suite.ctx, req)
|
||||
if tc.expPass {
|
||||
suite.Require().NotNil(res)
|
||||
suite.Require().NoError(err)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestEmptyRequest() {
|
||||
k := suite.app.EvmKeeper
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
queryFunc func() (interface{}, error)
|
||||
}{
|
||||
{
|
||||
"Account method",
|
||||
func() (interface{}, error) {
|
||||
return k.Account(suite.ctx, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
"CosmosAccount method",
|
||||
func() (interface{}, error) {
|
||||
return k.CosmosAccount(suite.ctx, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
"ValidatorAccount method",
|
||||
func() (interface{}, error) {
|
||||
return k.ValidatorAccount(suite.ctx, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
"Balance method",
|
||||
func() (interface{}, error) {
|
||||
return k.Balance(suite.ctx, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
"Storage method",
|
||||
func() (interface{}, error) {
|
||||
return k.Storage(suite.ctx, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
"Code method",
|
||||
func() (interface{}, error) {
|
||||
return k.Code(suite.ctx, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
"EthCall method",
|
||||
func() (interface{}, error) {
|
||||
return k.EthCall(suite.ctx, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
"EstimateGas method",
|
||||
func() (interface{}, error) {
|
||||
return k.EstimateGas(suite.ctx, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
"TraceTx method",
|
||||
func() (interface{}, error) {
|
||||
return k.TraceTx(suite.ctx, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
"TraceBlock method",
|
||||
func() (interface{}, error) {
|
||||
return k.TraceBlock(suite.ctx, nil)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
|
||||
suite.SetupTest()
|
||||
_, err := tc.queryFunc()
|
||||
suite.Require().Error(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -200,6 +200,7 @@ func (suite *KeeperTestSuite) SetupApp(checkTx bool) {
|
||||
|
||||
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)
|
||||
@ -434,3 +435,88 @@ func (suite *KeeperTestSuite) TestBaseFee() {
|
||||
suite.enableFeemarket = false
|
||||
suite.enableLondonHF = true
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestGetAccountStorage() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
malleate func()
|
||||
expRes []int
|
||||
}{
|
||||
{
|
||||
"Only one account that's not a contract (no storage)",
|
||||
func() {},
|
||||
[]int{0},
|
||||
},
|
||||
{
|
||||
"Two accounts - one contract (with storage), one wallet",
|
||||
func() {
|
||||
supply := big.NewInt(100)
|
||||
suite.DeployTestContract(suite.T(), suite.address, supply)
|
||||
},
|
||||
[]int{2, 0},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest()
|
||||
tc.malleate()
|
||||
i := 0
|
||||
suite.app.AccountKeeper.IterateAccounts(suite.ctx, func(account authtypes.AccountI) bool {
|
||||
ethAccount, ok := account.(ethermint.EthAccountI)
|
||||
if !ok {
|
||||
// ignore non EthAccounts
|
||||
return false
|
||||
}
|
||||
|
||||
addr := ethAccount.EthAddress()
|
||||
storage := suite.app.EvmKeeper.GetAccountStorage(suite.ctx, addr)
|
||||
|
||||
suite.Require().Equal(tc.expRes[i], len(storage))
|
||||
i++
|
||||
return false
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestGetAccountOrEmpty() {
|
||||
empty := statedb.Account{
|
||||
Balance: new(big.Int),
|
||||
CodeHash: types.EmptyCodeHash,
|
||||
}
|
||||
|
||||
supply := big.NewInt(100)
|
||||
contractAddr := suite.DeployTestContract(suite.T(), suite.address, supply)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
addr common.Address
|
||||
expEmpty bool
|
||||
}{
|
||||
{
|
||||
"unexisting account - get empty",
|
||||
common.Address{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"existing contract account",
|
||||
contractAddr,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
res := suite.app.EvmKeeper.GetAccountOrEmpty(suite.ctx, tc.addr)
|
||||
if tc.expEmpty {
|
||||
suite.Require().Equal(empty, res)
|
||||
} else {
|
||||
suite.Require().NotEqual(empty, res)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
31
x/evm/keeper/migrations_test.go
Normal file
31
x/evm/keeper/migrations_test.go
Normal file
@ -0,0 +1,31 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
evmkeeper "github.com/evmos/ethermint/x/evm/keeper"
|
||||
)
|
||||
|
||||
func (suite *KeeperTestSuite) TestMigrations() {
|
||||
migrator := evmkeeper.NewMigrator(*suite.app.EvmKeeper)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
migrateFunc func(ctx sdk.Context) error
|
||||
}{
|
||||
{
|
||||
"Run Migrate1to2",
|
||||
migrator.Migrate1to2,
|
||||
},
|
||||
{
|
||||
"Run Migrate2to3",
|
||||
migrator.Migrate2to3,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
err := tc.migrateFunc(suite.ctx)
|
||||
suite.Require().NoError(err)
|
||||
})
|
||||
}
|
||||
}
|
80
x/evm/keeper/msg_server_test.go
Normal file
80
x/evm/keeper/msg_server_test.go
Normal file
@ -0,0 +1,80 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/evmos/ethermint/x/evm/statedb"
|
||||
"github.com/evmos/ethermint/x/evm/types"
|
||||
)
|
||||
|
||||
func (suite *KeeperTestSuite) TestEthereumTx() {
|
||||
var (
|
||||
err error
|
||||
msg *types.MsgEthereumTx
|
||||
signer ethtypes.Signer
|
||||
vmdb *statedb.StateDB
|
||||
chainCfg *params.ChainConfig
|
||||
expectedGasUsed uint64
|
||||
)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
malleate func()
|
||||
expErr bool
|
||||
}{
|
||||
{
|
||||
"Deploy contract tx - insufficient gas",
|
||||
func() {
|
||||
msg, err = suite.createContractMsgTx(
|
||||
vmdb.GetNonce(suite.address),
|
||||
signer,
|
||||
chainCfg,
|
||||
big.NewInt(1),
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Transfer funds tx",
|
||||
func() {
|
||||
msg, _, err = newEthMsgTx(
|
||||
vmdb.GetNonce(suite.address),
|
||||
suite.ctx.BlockHeight(),
|
||||
suite.address,
|
||||
chainCfg,
|
||||
suite.signer,
|
||||
signer,
|
||||
ethtypes.AccessListTxType,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
expectedGasUsed = params.TxGas
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest()
|
||||
keeperParams := suite.app.EvmKeeper.GetParams(suite.ctx)
|
||||
chainCfg = keeperParams.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID())
|
||||
signer = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
|
||||
vmdb = suite.StateDB()
|
||||
|
||||
tc.malleate()
|
||||
res, err := suite.app.EvmKeeper.EthereumTx(suite.ctx, msg)
|
||||
if tc.expErr {
|
||||
suite.Require().Error(err)
|
||||
return
|
||||
}
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(expectedGasUsed, res.GasUsed)
|
||||
suite.Require().False(res.Failed())
|
||||
})
|
||||
}
|
||||
}
|
@ -75,7 +75,7 @@ func newSignedEthTx(
|
||||
return ethTx, nil
|
||||
}
|
||||
|
||||
func newNativeMessage(
|
||||
func newEthMsgTx(
|
||||
nonce uint64,
|
||||
blockHeight int64,
|
||||
address common.Address,
|
||||
@ -85,14 +85,11 @@ func newNativeMessage(
|
||||
txType byte,
|
||||
data []byte,
|
||||
accessList ethtypes.AccessList,
|
||||
) (core.Message, error) {
|
||||
msgSigner := ethtypes.MakeSigner(cfg, big.NewInt(blockHeight))
|
||||
|
||||
) (*evmtypes.MsgEthereumTx, *big.Int, error) {
|
||||
var (
|
||||
ethTx *ethtypes.Transaction
|
||||
baseFee *big.Int
|
||||
)
|
||||
|
||||
switch txType {
|
||||
case ethtypes.LegacyTxType:
|
||||
templateLegacyTx.Nonce = nonce
|
||||
@ -122,14 +119,32 @@ func newNativeMessage(
|
||||
ethTx = ethtypes.NewTx(templateDynamicFeeTx)
|
||||
baseFee = big.NewInt(3)
|
||||
default:
|
||||
return nil, errors.New("unsupport tx type")
|
||||
return nil, baseFee, errors.New("unsupport tx type")
|
||||
}
|
||||
|
||||
msg := &evmtypes.MsgEthereumTx{}
|
||||
msg.FromEthereumTx(ethTx)
|
||||
msg.From = address.Hex()
|
||||
|
||||
if err := msg.Sign(ethSigner, krSigner); err != nil {
|
||||
return msg, baseFee, msg.Sign(ethSigner, krSigner)
|
||||
}
|
||||
|
||||
func newNativeMessage(
|
||||
nonce uint64,
|
||||
blockHeight int64,
|
||||
address common.Address,
|
||||
cfg *params.ChainConfig,
|
||||
krSigner keyring.Signer,
|
||||
ethSigner ethtypes.Signer,
|
||||
txType byte,
|
||||
data []byte,
|
||||
accessList ethtypes.AccessList,
|
||||
) (core.Message, error) {
|
||||
msgSigner := ethtypes.MakeSigner(cfg, big.NewInt(blockHeight))
|
||||
|
||||
msg, baseFee, err := newEthMsgTx(nonce, blockHeight, address, cfg, krSigner, ethSigner, txType, data, accessList)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -9,10 +9,12 @@ import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/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/params"
|
||||
"github.com/evmos/ethermint/tests"
|
||||
"github.com/evmos/ethermint/x/evm/keeper"
|
||||
"github.com/evmos/ethermint/x/evm/statedb"
|
||||
"github.com/evmos/ethermint/x/evm/types"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
@ -346,40 +348,63 @@ func (suite *KeeperTestSuite) TestGasToRefund() {
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestRefundGas() {
|
||||
var (
|
||||
m core.Message
|
||||
err error
|
||||
)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
leftoverGas uint64
|
||||
refundQuotient uint64
|
||||
noError bool
|
||||
expGasRefund uint64
|
||||
malleate func()
|
||||
}{
|
||||
{
|
||||
"leftoverGas more than tx gas limit",
|
||||
params.TxGas + 1,
|
||||
params.RefundQuotient,
|
||||
false,
|
||||
params.TxGas + 1,
|
||||
name: "leftoverGas more than tx gas limit",
|
||||
leftoverGas: params.TxGas + 1,
|
||||
refundQuotient: params.RefundQuotient,
|
||||
noError: false,
|
||||
expGasRefund: params.TxGas + 1,
|
||||
},
|
||||
{
|
||||
"leftoverGas equal to tx gas limit, insufficient fee collector account",
|
||||
params.TxGas,
|
||||
params.RefundQuotient,
|
||||
true,
|
||||
0,
|
||||
name: "leftoverGas equal to tx gas limit, insufficient fee collector account",
|
||||
leftoverGas: params.TxGas,
|
||||
refundQuotient: params.RefundQuotient,
|
||||
noError: true,
|
||||
expGasRefund: 0,
|
||||
},
|
||||
{
|
||||
"leftoverGas less than to tx gas limit",
|
||||
params.TxGas - 1,
|
||||
params.RefundQuotient,
|
||||
true,
|
||||
0,
|
||||
name: "leftoverGas less than to tx gas limit",
|
||||
leftoverGas: params.TxGas - 1,
|
||||
refundQuotient: params.RefundQuotient,
|
||||
noError: true,
|
||||
expGasRefund: 0,
|
||||
},
|
||||
{
|
||||
"no leftoverGas, refund half used gas ",
|
||||
0,
|
||||
params.RefundQuotient,
|
||||
true,
|
||||
params.TxGas / params.RefundQuotient,
|
||||
name: "no leftoverGas, refund half used gas ",
|
||||
leftoverGas: 0,
|
||||
refundQuotient: params.RefundQuotient,
|
||||
noError: true,
|
||||
expGasRefund: params.TxGas / params.RefundQuotient,
|
||||
},
|
||||
{
|
||||
name: "invalid Gas value in msg",
|
||||
leftoverGas: 0,
|
||||
refundQuotient: params.RefundQuotient,
|
||||
noError: false,
|
||||
expGasRefund: params.TxGas,
|
||||
malleate: func() {
|
||||
keeperParams := suite.app.EvmKeeper.GetParams(suite.ctx)
|
||||
m, err = suite.createContractGethMsg(
|
||||
suite.StateDB().GetNonce(suite.address),
|
||||
ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID()),
|
||||
keeperParams.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID()),
|
||||
big.NewInt(-100),
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -393,7 +418,7 @@ func (suite *KeeperTestSuite) TestRefundGas() {
|
||||
signer := ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
|
||||
vmdb := suite.StateDB()
|
||||
|
||||
m, err := newNativeMessage(
|
||||
m, err = newNativeMessage(
|
||||
vmdb.GetNonce(suite.address),
|
||||
suite.ctx.BlockHeight(),
|
||||
suite.address,
|
||||
@ -411,6 +436,11 @@ func (suite *KeeperTestSuite) TestRefundGas() {
|
||||
if tc.leftoverGas > m.Gas() {
|
||||
return
|
||||
}
|
||||
|
||||
if tc.malleate != nil {
|
||||
tc.malleate()
|
||||
}
|
||||
|
||||
gasUsed := m.Gas() - tc.leftoverGas
|
||||
refund := keeper.GasToRefund(vmdb.GetRefund(), gasUsed, tc.refundQuotient)
|
||||
suite.Require().Equal(tc.expGasRefund, refund)
|
||||
@ -486,7 +516,6 @@ func (suite *KeeperTestSuite) TestResetGasMeterAndConsumeGas() {
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestEVMConfig() {
|
||||
suite.SetupTest()
|
||||
cfg, err := suite.app.EvmKeeper.EVMConfig(suite.ctx)
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(types.DefaultParams(), cfg.Params)
|
||||
@ -497,8 +526,165 @@ func (suite *KeeperTestSuite) TestEVMConfig() {
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestContractDeployment() {
|
||||
suite.SetupTest()
|
||||
contractAddress := suite.DeployTestContract(suite.T(), suite.address, big.NewInt(10000000000000))
|
||||
db := suite.StateDB()
|
||||
suite.Require().Greater(db.GetCodeSize(contractAddress), 0)
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestApplyMessage() {
|
||||
expectedGasUsed := params.TxGas
|
||||
var msg core.Message
|
||||
|
||||
config, err := suite.app.EvmKeeper.EVMConfig(suite.ctx)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
keeperParams := suite.app.EvmKeeper.GetParams(suite.ctx)
|
||||
chainCfg := keeperParams.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID())
|
||||
signer := ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
|
||||
tracer := suite.app.EvmKeeper.Tracer(suite.ctx, msg, config.ChainConfig)
|
||||
vmdb := suite.StateDB()
|
||||
|
||||
msg, err = newNativeMessage(
|
||||
vmdb.GetNonce(suite.address),
|
||||
suite.ctx.BlockHeight(),
|
||||
suite.address,
|
||||
chainCfg,
|
||||
suite.signer,
|
||||
signer,
|
||||
ethtypes.AccessListTxType,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
res, err := suite.app.EvmKeeper.ApplyMessage(suite.ctx, msg, tracer, true)
|
||||
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(expectedGasUsed, res.GasUsed)
|
||||
suite.Require().False(res.Failed())
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestApplyMessageWithConfig() {
|
||||
var (
|
||||
msg core.Message
|
||||
err error
|
||||
expectedGasUsed uint64
|
||||
config *types.EVMConfig
|
||||
keeperParams types.Params
|
||||
signer ethtypes.Signer
|
||||
vmdb *statedb.StateDB
|
||||
txConfig statedb.TxConfig
|
||||
chainCfg *params.ChainConfig
|
||||
)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
malleate func()
|
||||
expErr bool
|
||||
}{
|
||||
{
|
||||
"messsage applied ok",
|
||||
func() {
|
||||
msg, err = newNativeMessage(
|
||||
vmdb.GetNonce(suite.address),
|
||||
suite.ctx.BlockHeight(),
|
||||
suite.address,
|
||||
chainCfg,
|
||||
suite.signer,
|
||||
signer,
|
||||
ethtypes.AccessListTxType,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"call contract tx with config param EnableCall = false",
|
||||
func() {
|
||||
config.Params.EnableCall = false
|
||||
msg, err = newNativeMessage(
|
||||
vmdb.GetNonce(suite.address),
|
||||
suite.ctx.BlockHeight(),
|
||||
suite.address,
|
||||
chainCfg,
|
||||
suite.signer,
|
||||
signer,
|
||||
ethtypes.AccessListTxType,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"create contract tx with config param EnableCreate = false",
|
||||
func() {
|
||||
msg, err = suite.createContractGethMsg(vmdb.GetNonce(suite.address), signer, chainCfg, big.NewInt(1))
|
||||
suite.Require().NoError(err)
|
||||
config.Params.EnableCreate = false
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
|
||||
suite.SetupTest()
|
||||
expectedGasUsed = params.TxGas
|
||||
|
||||
config, err = suite.app.EvmKeeper.EVMConfig(suite.ctx)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
keeperParams = suite.app.EvmKeeper.GetParams(suite.ctx)
|
||||
chainCfg = keeperParams.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID())
|
||||
signer = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
|
||||
vmdb = suite.StateDB()
|
||||
txConfig = suite.app.EvmKeeper.TxConfig(suite.ctx, common.Hash{})
|
||||
|
||||
tc.malleate()
|
||||
res, err := suite.app.EvmKeeper.ApplyMessageWithConfig(suite.ctx, msg, nil, true, config, txConfig)
|
||||
|
||||
if tc.expErr {
|
||||
suite.Require().Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().False(res.Failed())
|
||||
suite.Require().Equal(expectedGasUsed, res.GasUsed)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) createContractGethMsg(nonce uint64, signer ethtypes.Signer, cfg *params.ChainConfig, gasPrice *big.Int) (core.Message, error) {
|
||||
|
||||
ethMsg, err := suite.createContractMsgTx(nonce, signer, cfg, gasPrice)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgSigner := ethtypes.MakeSigner(cfg, big.NewInt(suite.ctx.BlockHeight()))
|
||||
return ethMsg.AsMessage(msgSigner, nil)
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) createContractMsgTx(nonce uint64, signer ethtypes.Signer, cfg *params.ChainConfig, gasPrice *big.Int) (*types.MsgEthereumTx, error) {
|
||||
|
||||
contractCreateTx := ðtypes.AccessListTx{
|
||||
GasPrice: gasPrice,
|
||||
Gas: params.TxGasContractCreation,
|
||||
To: nil,
|
||||
Data: []byte("contract_data"),
|
||||
Nonce: nonce,
|
||||
}
|
||||
ethTx := ethtypes.NewTx(contractCreateTx)
|
||||
ethMsg := &types.MsgEthereumTx{}
|
||||
ethMsg.FromEthereumTx(ethTx)
|
||||
ethMsg.From = suite.address.Hex()
|
||||
|
||||
return ethMsg, ethMsg.Sign(signer, suite.signer)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/store/prefix"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
@ -317,6 +318,40 @@ func (suite *KeeperTestSuite) TestSetCode() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestKeeperSetCode() {
|
||||
addr := tests.GenerateAddress()
|
||||
baseAcc := &authtypes.BaseAccount{Address: sdk.AccAddress(addr.Bytes()).String()}
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, baseAcc)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
codeHash []byte
|
||||
code []byte
|
||||
}{
|
||||
{
|
||||
"set code",
|
||||
[]byte("codeHash"),
|
||||
[]byte("this is the code"),
|
||||
},
|
||||
{
|
||||
"delete code",
|
||||
[]byte("codeHash"),
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.app.EvmKeeper.SetCode(suite.ctx, tc.codeHash, tc.code)
|
||||
key := suite.app.GetKey(types.StoreKey)
|
||||
store := prefix.NewStore(suite.ctx.KVStore(key), types.KeyPrefixCode)
|
||||
code := store.Get(tc.codeHash)
|
||||
|
||||
suite.Require().Equal(tc.code, code)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestRefund() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
@ -384,8 +419,6 @@ func (suite *KeeperTestSuite) TestState() {
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestCommittedState() {
|
||||
suite.SetupTest()
|
||||
|
||||
key := common.BytesToHash([]byte("key"))
|
||||
value1 := common.BytesToHash([]byte("value1"))
|
||||
value2 := common.BytesToHash([]byte("value2"))
|
||||
@ -487,8 +520,6 @@ func (suite *KeeperTestSuite) TestExist() {
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestEmpty() {
|
||||
suite.SetupTest()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
address common.Address
|
||||
@ -507,6 +538,7 @@ func (suite *KeeperTestSuite) TestEmpty() {
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest()
|
||||
vmdb := suite.StateDB()
|
||||
tc.malleate(vmdb)
|
||||
|
||||
@ -811,3 +843,102 @@ func (suite *KeeperTestSuite) _TestForEachStorage() {
|
||||
storage = types.Storage{}
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestSetBalance() {
|
||||
amount := big.NewInt(-10)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
addr common.Address
|
||||
malleate func()
|
||||
expErr bool
|
||||
}{
|
||||
{
|
||||
"address without funds - invalid amount",
|
||||
suite.address,
|
||||
func() {},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"mint to address",
|
||||
suite.address,
|
||||
func() {
|
||||
amount = big.NewInt(100)
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"burn from address",
|
||||
suite.address,
|
||||
func() {
|
||||
amount = big.NewInt(60)
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"address with funds - invalid amount",
|
||||
suite.address,
|
||||
func() {
|
||||
amount = big.NewInt(-10)
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest()
|
||||
tc.malleate()
|
||||
err := suite.app.EvmKeeper.SetBalance(suite.ctx, tc.addr, amount)
|
||||
if tc.expErr {
|
||||
suite.Require().Error(err)
|
||||
} else {
|
||||
balance := suite.app.EvmKeeper.GetBalance(suite.ctx, tc.addr)
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(amount, balance)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestDeleteAccount() {
|
||||
supply := big.NewInt(100)
|
||||
contractAddr := suite.DeployTestContract(suite.T(), suite.address, supply)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
addr common.Address
|
||||
expErr bool
|
||||
}{
|
||||
{
|
||||
"remove address",
|
||||
suite.address,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"remove unexistent address - returns nil error",
|
||||
common.HexToAddress("unexistent_address"),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"remove deployed contract",
|
||||
contractAddr,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest()
|
||||
err := suite.app.EvmKeeper.DeleteAccount(suite.ctx, tc.addr)
|
||||
if tc.expErr {
|
||||
suite.Require().Error(err)
|
||||
} else {
|
||||
suite.Require().NoError(err)
|
||||
balance := suite.app.EvmKeeper.GetBalance(suite.ctx, tc.addr)
|
||||
suite.Require().Equal(new(big.Int), balance)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -271,6 +271,8 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
accessList *ethtypes.AccessList
|
||||
expectPass bool
|
||||
enableFeemarket bool
|
||||
from string
|
||||
malleate func()
|
||||
}{
|
||||
{
|
||||
name: "Enough balance",
|
||||
@ -279,6 +281,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
cost: &oneInt,
|
||||
accessList: ðtypes.AccessList{},
|
||||
expectPass: true,
|
||||
from: suite.address.String(),
|
||||
},
|
||||
{
|
||||
name: "Equal balance",
|
||||
@ -287,6 +290,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
cost: &oneInt,
|
||||
accessList: ðtypes.AccessList{},
|
||||
expectPass: true,
|
||||
from: suite.address.String(),
|
||||
},
|
||||
{
|
||||
name: "Higher gas limit, not enough balance",
|
||||
@ -295,6 +299,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
cost: &oneInt,
|
||||
accessList: ðtypes.AccessList{},
|
||||
expectPass: false,
|
||||
from: suite.address.String(),
|
||||
},
|
||||
{
|
||||
name: "Higher gas price, enough balance",
|
||||
@ -303,6 +308,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
cost: &oneInt,
|
||||
accessList: ðtypes.AccessList{},
|
||||
expectPass: true,
|
||||
from: suite.address.String(),
|
||||
},
|
||||
{
|
||||
name: "Higher gas price, not enough balance",
|
||||
@ -311,6 +317,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
cost: &oneInt,
|
||||
accessList: ðtypes.AccessList{},
|
||||
expectPass: false,
|
||||
from: suite.address.String(),
|
||||
},
|
||||
// This case is expected to be true because the fees can be deducted, but the tx
|
||||
// execution is going to fail because there is no more balance to pay the cost
|
||||
@ -321,6 +328,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
cost: &fiftyInt,
|
||||
accessList: ðtypes.AccessList{},
|
||||
expectPass: true,
|
||||
from: suite.address.String(),
|
||||
},
|
||||
// testcases with enableFeemarket enabled.
|
||||
{
|
||||
@ -332,6 +340,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
accessList: ðtypes.AccessList{},
|
||||
expectPass: false,
|
||||
enableFeemarket: true,
|
||||
from: suite.address.String(),
|
||||
},
|
||||
{
|
||||
name: "empty tip fee is valid to deduct",
|
||||
@ -342,6 +351,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
accessList: ðtypes.AccessList{},
|
||||
expectPass: true,
|
||||
enableFeemarket: true,
|
||||
from: suite.address.String(),
|
||||
},
|
||||
{
|
||||
name: "effectiveTip equal to gasTipCap",
|
||||
@ -351,6 +361,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
accessList: ðtypes.AccessList{},
|
||||
expectPass: true,
|
||||
enableFeemarket: true,
|
||||
from: suite.address.String(),
|
||||
},
|
||||
{
|
||||
name: "effectiveTip equal to (gasFeeCap - baseFee)",
|
||||
@ -361,6 +372,42 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
accessList: ðtypes.AccessList{},
|
||||
expectPass: true,
|
||||
enableFeemarket: true,
|
||||
from: suite.address.String(),
|
||||
},
|
||||
{
|
||||
name: "Invalid from address",
|
||||
gasLimit: 10,
|
||||
gasPrice: &oneInt,
|
||||
cost: &oneInt,
|
||||
accessList: ðtypes.AccessList{},
|
||||
expectPass: false,
|
||||
from: "",
|
||||
},
|
||||
{
|
||||
name: "Enough balance - with access list",
|
||||
gasLimit: 10,
|
||||
gasPrice: &oneInt,
|
||||
cost: &oneInt,
|
||||
accessList: ðtypes.AccessList{
|
||||
ethtypes.AccessTuple{
|
||||
Address: suite.address,
|
||||
StorageKeys: []common.Hash{},
|
||||
},
|
||||
},
|
||||
expectPass: true,
|
||||
from: suite.address.String(),
|
||||
},
|
||||
{
|
||||
name: "gasLimit < intrinsicGas during IsCheckTx",
|
||||
gasLimit: 1,
|
||||
gasPrice: &oneInt,
|
||||
cost: &oneInt,
|
||||
accessList: ðtypes.AccessList{},
|
||||
expectPass: false,
|
||||
from: suite.address.String(),
|
||||
malleate: func() {
|
||||
suite.ctx = suite.ctx.WithIsCheckTx(true)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -370,6 +417,9 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
suite.SetupTest()
|
||||
vmdb := suite.StateDB()
|
||||
|
||||
if tc.malleate != nil {
|
||||
tc.malleate()
|
||||
}
|
||||
var amount, gasPrice, gasFeeCap, gasTipCap *big.Int
|
||||
if tc.cost != nil {
|
||||
amount = tc.cost.BigInt()
|
||||
@ -399,7 +449,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
vmdb.Commit()
|
||||
|
||||
tx := evmtypes.NewTx(zeroInt.BigInt(), 1, &suite.address, amount, tc.gasLimit, gasPrice, gasFeeCap, gasTipCap, nil, tc.accessList)
|
||||
tx.From = suite.address.String()
|
||||
tx.From = tc.from
|
||||
|
||||
txData, _ := evmtypes.UnpackTxData(tx.Data)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user