update fork

This commit is contained in:
0xmuralik
2022-10-10 16:08:33 +05:30
parent 632d53e34a
commit 56d59feaa0
383 changed files with 36784 additions and 21462 deletions
+9 -9
View File
@@ -4,21 +4,21 @@ import (
"math/big"
"testing"
"cosmossdk.io/math"
sdkmath "cosmossdk.io/math"
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/ethereum/go-ethereum/common"
ethermint "github.com/cerc-io/laconicd/types"
"github.com/cerc-io/laconicd/x/evm/types"
ante "github.com/cosmos/cosmos-sdk/x/auth/ante"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
func SetupContract(b *testing.B) (*KeeperTestSuite, common.Address) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
amt := sdk.Coins{ethermint.NewPhotonCoinInt64(1000000000000000000)}
err := suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, amt)
@@ -26,7 +26,7 @@ func SetupContract(b *testing.B) (*KeeperTestSuite, common.Address) {
err = suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, suite.address.Bytes(), amt)
require.NoError(b, err)
contractAddr := suite.DeployTestContract(b, suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(b, suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
return &suite, contractAddr
@@ -34,7 +34,7 @@ func SetupContract(b *testing.B) (*KeeperTestSuite, common.Address) {
func SetupTestMessageCall(b *testing.B) (*KeeperTestSuite, common.Address) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
amt := sdk.Coins{ethermint.NewPhotonCoinInt64(1000000000000000000)}
err := suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, amt)
@@ -67,8 +67,8 @@ func DoBenchmark(b *testing.B, txBuilder TxBuilder) {
txData, err := types.UnpackTxData(msg.Data)
require.NoError(b, err)
fees := sdk.Coins{sdk.NewCoin(suite.EvmDenom(), sdk.NewIntFromBigInt(txData.Fee()))}
err = ante.DeductFees(suite.app.BankKeeper, suite.ctx, suite.app.AccountKeeper.GetAccount(ctx, msg.GetFrom()), fees)
fees := sdk.Coins{sdk.NewCoin(suite.EvmDenom(), sdkmath.NewIntFromBigInt(txData.Fee()))}
err = authante.DeductFees(suite.app.BankKeeper, suite.ctx, suite.app.AccountKeeper.GetAccount(ctx, msg.GetFrom()), fees)
require.NoError(b, err)
rsp, err := suite.app.EvmKeeper.EthereumTx(sdk.WrapSDKContext(ctx), msg)
@@ -134,8 +134,8 @@ func BenchmarkMessageCall(b *testing.B) {
txData, err := types.UnpackTxData(msg.Data)
require.NoError(b, err)
fees := sdk.Coins{sdk.NewCoin(suite.EvmDenom(), sdk.NewIntFromBigInt(txData.Fee()))}
err = ante.DeductFees(suite.app.BankKeeper, suite.ctx, suite.app.AccountKeeper.GetAccount(ctx, msg.GetFrom()), fees)
fees := sdk.Coins{sdk.NewCoin(suite.EvmDenom(), sdkmath.NewIntFromBigInt(txData.Fee()))}
err = authante.DeductFees(suite.app.BankKeeper, suite.ctx, suite.app.AccountKeeper.GetAccount(ctx, msg.GetFrom()), fees)
require.NoError(b, err)
rsp, err := suite.app.EvmKeeper.EthereumTx(sdk.WrapSDKContext(ctx), msg)
+85 -74
View File
@@ -15,6 +15,7 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
@@ -88,6 +89,7 @@ func (k Keeper) CosmosAccount(c context.Context, req *types.QueryCosmosAccountRe
return &res, nil
}
// ValidatorAccount implements the Query/Balance gRPC method
func (k Keeper) ValidatorAccount(c context.Context, req *types.QueryValidatorAccountRequest) (*types.QueryValidatorAccountResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
@@ -104,7 +106,7 @@ func (k Keeper) ValidatorAccount(c context.Context, req *types.QueryValidatorAcc
validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr)
if !found {
return nil, nil
return nil, fmt.Errorf("validator not found for %s", consAddr.String())
}
accAddr := sdk.AccAddress(validator.GetOperator())
@@ -362,8 +364,15 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ
return nil, status.Errorf(codes.InvalidArgument, "output limit cannot be negative, got %d", req.TraceConfig.Limit)
}
// minus one to get the context of block beginning
contextHeight := req.BlockNumber - 1
if contextHeight < 1 {
// 0 is a special value in `ContextWithHeight`
contextHeight = 1
}
ctx := sdk.UnwrapSDKContext(c)
ctx = ctx.WithBlockHeight(req.BlockNumber)
ctx = ctx.WithBlockHeight(contextHeight)
ctx = ctx.WithBlockTime(req.BlockTime)
ctx = ctx.WithHeaderHash(common.Hex2Bytes(req.BlockHash))
@@ -391,7 +400,10 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ
tx := req.Msg.AsTransaction()
txConfig.TxHash = tx.Hash()
txConfig.TxIndex++
if len(req.Predecessors) > 0 {
txConfig.TxIndex++
}
result, _, err := k.traceTx(ctx, cfg, txConfig, signer, tx, req.TraceConfig, false)
if err != nil {
// error will be returned with detail status from traceTx
@@ -420,8 +432,15 @@ func (k Keeper) TraceBlock(c context.Context, req *types.QueryTraceBlockRequest)
return nil, status.Errorf(codes.InvalidArgument, "output limit cannot be negative, got %d", req.TraceConfig.Limit)
}
// minus one to get the context of block beginning
contextHeight := req.BlockNumber - 1
if contextHeight < 1 {
// 0 is a special value in `ContextWithHeight`
contextHeight = 1
}
ctx := sdk.UnwrapSDKContext(c)
ctx = ctx.WithBlockHeight(req.BlockNumber)
ctx = ctx.WithBlockHeight(contextHeight)
ctx = ctx.WithBlockTime(req.BlockTime)
ctx = ctx.WithHeaderHash(common.Hex2Bytes(req.BlockHash))
@@ -471,101 +490,93 @@ func (k *Keeper) traceTx(
) (*interface{}, uint, error) {
// Assemble the structured logger or the JavaScript tracer
var (
tracer vm.EVMLogger
tracer tracers.Tracer
overrides *ethparams.ChainConfig
err error
timeout = defaultTraceTimeout
)
msg, err := tx.AsMessage(signer, cfg.BaseFee)
if err != nil {
return nil, 0, status.Error(codes.Internal, err.Error())
}
if traceConfig != nil && traceConfig.Overrides != nil {
if traceConfig == nil {
traceConfig = &types.TraceConfig{}
}
if traceConfig.Overrides != nil {
overrides = traceConfig.Overrides.EthereumConfig(cfg.ChainConfig.ChainID)
}
switch {
case traceConfig != nil && traceConfig.Tracer != "":
timeout := defaultTraceTimeout
// TODO: change timeout to time.duration
// Used string to comply with go ethereum
if traceConfig.Timeout != "" {
timeout, err = time.ParseDuration(traceConfig.Timeout)
if err != nil {
return nil, 0, status.Errorf(codes.InvalidArgument, "timeout value: %s", err.Error())
}
}
logConfig := logger.Config{
EnableMemory: traceConfig.EnableMemory,
DisableStorage: traceConfig.DisableStorage,
DisableStack: traceConfig.DisableStack,
EnableReturnData: traceConfig.EnableReturnData,
Debug: traceConfig.Debug,
Limit: int(traceConfig.Limit),
Overrides: overrides,
}
tCtx := &tracers.Context{
BlockHash: txConfig.BlockHash,
TxIndex: int(txConfig.TxIndex),
TxHash: txConfig.TxHash,
}
tracer = logger.NewStructLogger(&logConfig)
// Construct the JavaScript tracer to execute with
tCtx := &tracers.Context{
BlockHash: txConfig.BlockHash,
TxIndex: int(txConfig.TxIndex),
TxHash: txConfig.TxHash,
}
if traceConfig.Tracer != "" {
if tracer, err = tracers.New(traceConfig.Tracer, tCtx); err != nil {
return nil, 0, status.Error(codes.Internal, err.Error())
}
// Handle timeouts and RPC cancellations
deadlineCtx, cancel := context.WithTimeout(ctx.Context(), timeout)
defer cancel()
go func() {
<-deadlineCtx.Done()
if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
tracer.(tracers.Tracer).Stop(errors.New("execution timeout"))
}
}()
case traceConfig != nil:
logConfig := logger.Config{
EnableMemory: traceConfig.EnableMemory,
DisableStorage: traceConfig.DisableStorage,
DisableStack: traceConfig.DisableStack,
EnableReturnData: traceConfig.EnableReturnData,
Debug: traceConfig.Debug,
Limit: int(traceConfig.Limit),
Overrides: overrides,
}
tracer = logger.NewStructLogger(&logConfig)
default:
tracer = types.NewTracer(types.TracerStruct, msg, cfg.ChainConfig, ctx.BlockHeight())
}
// Define a meaningful timeout of a single transaction trace
if traceConfig.Timeout != "" {
if timeout, err = time.ParseDuration(traceConfig.Timeout); err != nil {
return nil, 0, status.Errorf(codes.InvalidArgument, "timeout value: %s", err.Error())
}
}
// Handle timeouts and RPC cancellations
deadlineCtx, cancel := context.WithTimeout(ctx.Context(), timeout)
defer cancel()
go func() {
<-deadlineCtx.Done()
if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
tracer.Stop(errors.New("execution timeout"))
}
}()
res, err := k.ApplyMessageWithConfig(ctx, msg, tracer, commitMessage, cfg, txConfig)
if err != nil {
return nil, 0, status.Error(codes.Internal, err.Error())
}
var result interface{}
// Depending on the tracer type, format and return the trace result data.
switch tracer := tracer.(type) {
case *logger.StructLogger:
returnVal := ""
revert := res.Revert()
if len(revert) > 0 {
returnVal = fmt.Sprintf("%x", revert)
} else {
returnVal = fmt.Sprintf("%x", res.Return())
}
result = types.ExecutionResult{
Gas: res.GasUsed,
Failed: res.Failed(),
ReturnValue: returnVal,
StructLogs: types.FormatLogs(tracer.StructLogs()),
}
case tracers.Tracer:
result, err = tracer.GetResult()
if err != nil {
return nil, 0, status.Error(codes.Internal, err.Error())
}
default:
return nil, 0, status.Errorf(codes.InvalidArgument, "invalid tracer type %T", tracer)
result, err = tracer.GetResult()
if err != nil {
return nil, 0, status.Error(codes.Internal, err.Error())
}
return &result, txConfig.LogIndex + uint(len(res.Logs)), nil
}
// BaseFee implements the Query/BaseFee gRPC method
func (k Keeper) BaseFee(c context.Context, _ *types.QueryBaseFeeRequest) (*types.QueryBaseFeeResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
params := k.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID)
baseFee := k.GetBaseFee(ctx, ethCfg)
res := &types.QueryBaseFeeResponse{}
if baseFee != nil {
aux := sdkmath.NewIntFromBigInt(baseFee)
res.BaseFee = &aux
}
return res, nil
}
+115 -42
View File
@@ -5,12 +5,15 @@ import (
"fmt"
"math/big"
"cosmossdk.io/math"
sdkmath "cosmossdk.io/math"
"github.com/cerc-io/laconicd/x/evm/statedb"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
ethlogger "github.com/ethereum/go-ethereum/eth/tracers/logger"
ethparams "github.com/ethereum/go-ethereum/params"
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -523,7 +526,7 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
}, false, 0, false},
// estimate gas of an erc20 contract deployment, the exact gas number is checked with geth
{"contract deployment", func() {
ctorArgs, err := types.ERC20Contract.ABI.Pack("", &suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
ctorArgs, err := types.ERC20Contract.ABI.Pack("", &suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Require().NoError(err)
data := append(types.ERC20Contract.Bin, ctorArgs...)
args = types.TransactionArgs{
@@ -533,7 +536,7 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
}, true, 1186778, false},
// estimate gas of an erc20 transfer, the exact gas number is checked with geth
{"erc20 transfer", func() {
contractAddr := suite.DeployTestContract(suite.T(), suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
transferData, err := types.ERC20Contract.ABI.Pack("transfer", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000))
suite.Require().NoError(err)
@@ -558,7 +561,7 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
gasCap = 20000
}, false, 0, true},
{"contract deployment w/ enableFeemarket", func() {
ctorArgs, err := types.ERC20Contract.ABI.Pack("", &suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
ctorArgs, err := types.ERC20Contract.ABI.Pack("", &suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Require().NoError(err)
data := append(types.ERC20Contract.Bin, ctorArgs...)
args = types.TransactionArgs{
@@ -567,7 +570,7 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
}
}, true, 1186778, true},
{"erc20 transfer w/ enableFeemarket", func() {
contractAddr := suite.DeployTestContract(suite.T(), suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
transferData, err := types.ERC20Contract.ABI.Pack("transfer", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000))
suite.Require().NoError(err)
@@ -606,7 +609,6 @@ func (suite *KeeperTestSuite) TestTraceTx() {
var (
txMsg *types.MsgEthereumTx
traceConfig *types.TraceConfig
txIndex uint64
predecessors []*types.MsgEthereumTx
)
@@ -614,23 +616,21 @@ func (suite *KeeperTestSuite) TestTraceTx() {
msg string
malleate func()
expPass bool
traceResponse []byte
traceResponse string
enableFeemarket bool
}{
{
msg: "default trace",
malleate: func() {
txIndex = 0
traceConfig = nil
predecessors = []*types.MsgEthereumTx{}
},
expPass: true,
traceResponse: []byte{0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55, 0x53, 0x48, 0x31, 0x22, 0x2c, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a},
traceResponse: "{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PUSH1\",\"gas\":",
},
{
msg: "default trace with filtered response",
malleate: func() {
txIndex = 0
traceConfig = &types.TraceConfig{
DisableStack: true,
DisableStorage: true,
@@ -639,25 +639,23 @@ func (suite *KeeperTestSuite) TestTraceTx() {
predecessors = []*types.MsgEthereumTx{}
},
expPass: true,
traceResponse: []byte{0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55, 0x53, 0x48, 0x31, 0x22, 0x2c, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a},
traceResponse: "{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PUSH1\",\"gas\":",
enableFeemarket: false,
},
{
msg: "javascript tracer",
malleate: func() {
txIndex = 0
traceConfig = &types.TraceConfig{
Tracer: "{data: [], fault: function(log) {}, step: function(log) { if(log.op.toString() == \"CALL\") this.data.push(log.stack.peek(0)); }, result: function() { return this.data; }}",
}
predecessors = []*types.MsgEthereumTx{}
},
expPass: true,
traceResponse: []byte{0x5b, 0x5d},
traceResponse: "[]",
},
{
msg: "default trace with enableFeemarket",
malleate: func() {
txIndex = 0
traceConfig = &types.TraceConfig{
DisableStack: true,
DisableStorage: true,
@@ -666,26 +664,24 @@ func (suite *KeeperTestSuite) TestTraceTx() {
predecessors = []*types.MsgEthereumTx{}
},
expPass: true,
traceResponse: []byte{0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55, 0x53, 0x48, 0x31, 0x22, 0x2c, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a},
traceResponse: "{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PUSH1\",\"gas\":",
enableFeemarket: true,
},
{
msg: "javascript tracer with enableFeemarket",
malleate: func() {
txIndex = 0
traceConfig = &types.TraceConfig{
Tracer: "{data: [], fault: function(log) {}, step: function(log) { if(log.op.toString() == \"CALL\") this.data.push(log.stack.peek(0)); }, result: function() { return this.data; }}",
}
predecessors = []*types.MsgEthereumTx{}
},
expPass: true,
traceResponse: []byte{0x5b, 0x5d},
traceResponse: "[]",
enableFeemarket: true,
},
{
msg: "default tracer with predecessors",
malleate: func() {
txIndex = 1
traceConfig = nil
// increase nonce to avoid address collision
@@ -693,17 +689,17 @@ func (suite *KeeperTestSuite) TestTraceTx() {
vmdb.SetNonce(suite.address, vmdb.GetNonce(suite.address)+1)
suite.Require().NoError(vmdb.Commit())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
// Generate token transfer transaction
firstTx := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), math.NewIntWithDecimal(1, 18).BigInt())
txMsg = suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), math.NewIntWithDecimal(1, 18).BigInt())
firstTx := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), sdkmath.NewIntWithDecimal(1, 18).BigInt())
txMsg = suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), sdkmath.NewIntWithDecimal(1, 18).BigInt())
suite.Commit()
predecessors = append(predecessors, firstTx)
},
expPass: true,
traceResponse: []byte{0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55, 0x53, 0x48, 0x31, 0x22, 0x2c, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a},
traceResponse: "{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PUSH1\",\"gas\":",
enableFeemarket: false,
},
}
@@ -713,17 +709,16 @@ func (suite *KeeperTestSuite) TestTraceTx() {
suite.enableFeemarket = tc.enableFeemarket
suite.SetupTest()
// Deploy contract
contractAddr := suite.DeployTestContract(suite.T(), suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
// Generate token transfer transaction
txMsg = suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), math.NewIntWithDecimal(1, 18).BigInt())
txMsg = suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), sdkmath.NewIntWithDecimal(1, 18).BigInt())
suite.Commit()
tc.malleate()
traceReq := types.QueryTraceTxRequest{
Msg: txMsg,
TraceConfig: traceConfig,
TxIndex: txIndex,
Predecessors: predecessors,
}
res, err := suite.queryClient.TraceTx(sdk.WrapSDKContext(suite.ctx), &traceReq)
@@ -733,9 +728,14 @@ func (suite *KeeperTestSuite) TestTraceTx() {
suite.Require().NoError(err)
// if data is to big, slice the result
if len(res.Data) > 150 {
suite.Require().Equal(tc.traceResponse, res.Data[:150])
suite.Require().Equal(tc.traceResponse, string(res.Data[:150]))
} else {
suite.Require().Equal(tc.traceResponse, res.Data)
suite.Require().Equal(tc.traceResponse, string(res.Data))
}
if traceConfig == nil || traceConfig.Tracer == "" {
var result ethlogger.ExecutionResult
suite.Require().NoError(json.Unmarshal(res.Data, &result))
suite.Require().Positive(result.Gas)
}
} else {
suite.Require().Error(err)
@@ -756,7 +756,7 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
msg string
malleate func()
expPass bool
traceResponse []byte
traceResponse string
enableFeemarket bool
}{
{
@@ -765,7 +765,7 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
traceConfig = nil
},
expPass: true,
traceResponse: []byte{0x5b, 0x7b, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55},
traceResponse: "[{\"result\":{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PU",
},
{
msg: "filtered trace",
@@ -777,7 +777,7 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
}
},
expPass: true,
traceResponse: []byte{0x5b, 0x7b, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55},
traceResponse: "[{\"result\":{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PU",
},
{
msg: "javascript tracer",
@@ -787,7 +787,7 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
}
},
expPass: true,
traceResponse: []byte{0x5b, 0x7b, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x5b, 0x5d, 0x7d, 0x5d},
traceResponse: "[{\"result\":[]}]",
},
{
msg: "default trace with enableFeemarket and filtered return",
@@ -799,7 +799,7 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
}
},
expPass: true,
traceResponse: []byte{0x5b, 0x7b, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55},
traceResponse: "[{\"result\":{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PU",
enableFeemarket: true,
},
{
@@ -810,7 +810,7 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
}
},
expPass: true,
traceResponse: []byte{0x5b, 0x7b, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x5b, 0x5d, 0x7d, 0x5d},
traceResponse: "[{\"result\":[]}]",
enableFeemarket: true,
},
{
@@ -823,17 +823,17 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
vmdb.SetNonce(suite.address, vmdb.GetNonce(suite.address)+1)
suite.Require().NoError(vmdb.Commit())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
// create multiple transactions in the same block
firstTx := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), math.NewIntWithDecimal(1, 18).BigInt())
secondTx := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), math.NewIntWithDecimal(1, 18).BigInt())
firstTx := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), sdkmath.NewIntWithDecimal(1, 18).BigInt())
secondTx := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), sdkmath.NewIntWithDecimal(1, 18).BigInt())
suite.Commit()
// overwrite txs to include only the ones on new block
txs = append([]*types.MsgEthereumTx{}, firstTx, secondTx)
},
expPass: true,
traceResponse: []byte{0x5b, 0x7b, 0x22, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x67, 0x61, 0x73, 0x22, 0x3a, 0x33, 0x34, 0x38, 0x32, 0x38, 0x2c, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x70, 0x63, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x22, 0x50, 0x55},
traceResponse: "[{\"result\":{\"gas\":34828,\"failed\":false,\"returnValue\":\"0000000000000000000000000000000000000000000000000000000000000001\",\"structLogs\":[{\"pc\":0,\"op\":\"PU",
enableFeemarket: false,
},
}
@@ -844,10 +844,10 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
suite.enableFeemarket = tc.enableFeemarket
suite.SetupTest()
// Deploy contract
contractAddr := suite.DeployTestContract(suite.T(), suite.address, math.NewIntWithDecimal(1000, 18).BigInt())
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
suite.Commit()
// Generate token transfer transaction
txMsg := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), math.NewIntWithDecimal(1, 18).BigInt())
txMsg := suite.TransferERC20Token(suite.T(), contractAddr, suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), sdkmath.NewIntWithDecimal(1, 18).BigInt())
suite.Commit()
txs = append(txs, txMsg)
@@ -863,9 +863,9 @@ func (suite *KeeperTestSuite) TestTraceBlock() {
suite.Require().NoError(err)
// if data is to big, slice the result
if len(res.Data) > 150 {
suite.Require().Equal(tc.traceResponse, res.Data[:150])
suite.Require().Equal(tc.traceResponse, string(res.Data[:150]))
} else {
suite.Require().Equal(tc.traceResponse, res.Data)
suite.Require().Equal(tc.traceResponse, string(res.Data))
}
} else {
suite.Require().Error(err)
@@ -882,7 +882,7 @@ func (suite *KeeperTestSuite) TestNonceInQuery() {
suite.Require().NoError(err)
address := common.BytesToAddress(priv.PubKey().Address().Bytes())
suite.Require().Equal(uint64(0), suite.app.EvmKeeper.GetNonce(suite.ctx, address))
supply := math.NewIntWithDecimal(1000, 18).BigInt()
supply := sdkmath.NewIntWithDecimal(1000, 18).BigInt()
// accupy nonce 0
_ = suite.DeployTestContract(suite.T(), address, supply)
@@ -908,3 +908,76 @@ func (suite *KeeperTestSuite) TestNonceInQuery() {
})
suite.Require().NoError(err)
}
func (suite *KeeperTestSuite) TestQueryBaseFee() {
var (
aux sdkmath.Int
expRes *types.QueryBaseFeeResponse
)
testCases := []struct {
name string
malleate func()
expPass bool
enableFeemarket bool
enableLondonHF bool
}{
{
"pass - default Base Fee",
func() {
initialBaseFee := sdkmath.NewInt(ethparams.InitialBaseFee)
expRes = &types.QueryBaseFeeResponse{BaseFee: &initialBaseFee}
},
true, true, true,
},
{
"pass - non-nil Base Fee",
func() {
baseFee := sdk.OneInt().BigInt()
suite.app.FeeMarketKeeper.SetBaseFee(suite.ctx, baseFee)
aux = sdkmath.NewIntFromBigInt(baseFee)
expRes = &types.QueryBaseFeeResponse{BaseFee: &aux}
},
true, true, true,
},
{
"pass - nil Base Fee when london hardfork not activated",
func() {
baseFee := sdk.OneInt().BigInt()
suite.app.FeeMarketKeeper.SetBaseFee(suite.ctx, baseFee)
expRes = &types.QueryBaseFeeResponse{}
},
true, true, false,
},
{
"pass - zero Base Fee when feemarket not activated",
func() {
baseFee := sdk.ZeroInt()
expRes = &types.QueryBaseFeeResponse{BaseFee: &baseFee}
},
true, false, true,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.enableFeemarket = tc.enableFeemarket
suite.enableLondonHF = tc.enableLondonHF
suite.SetupTest()
tc.malleate()
res, err := suite.queryClient.BaseFee(suite.ctx.Context(), &types.QueryBaseFeeRequest{})
if tc.expPass {
suite.Require().NotNil(res)
suite.Require().Equal(expRes, res, tc.name)
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
suite.enableFeemarket = false
suite.enableLondonHF = true
}
+3 -3
View File
@@ -4,7 +4,7 @@ import (
"github.com/cerc-io/laconicd/x/evm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
@@ -19,9 +19,9 @@ func NewMultiEvmHooks(hooks ...types.EvmHooks) MultiEvmHooks {
}
// PostTxProcessing delegate the call to underlying hooks
func (mh MultiEvmHooks) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
func (mh MultiEvmHooks) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
for i := range mh {
if err := mh[i].PostTxProcessing(ctx, from, to, receipt); err != nil {
if err := mh[i].PostTxProcessing(ctx, msg, receipt); err != nil {
return sdkerrors.Wrapf(err, "EVM hook %T failed", mh[i])
}
}
+4 -3
View File
@@ -6,6 +6,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/cerc-io/laconicd/x/evm/keeper"
@@ -18,7 +19,7 @@ type LogRecordHook struct {
Logs []*ethtypes.Log
}
func (dh *LogRecordHook) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
func (dh *LogRecordHook) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
dh.Logs = receipt.Logs
return nil
}
@@ -26,7 +27,7 @@ func (dh *LogRecordHook) PostTxProcessing(ctx sdk.Context, from common.Address,
// FailureHook always fail
type FailureHook struct{}
func (dh FailureHook) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
func (dh FailureHook) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
return errors.New("post tx processing failed")
}
@@ -81,7 +82,7 @@ func (suite *KeeperTestSuite) TestEvmHooks() {
TxHash: txHash,
Logs: logs,
}
result := k.PostTxProcessing(ctx, common.Address{}, nil, receipt)
result := k.PostTxProcessing(ctx, ethtypes.Message{}, receipt)
tc.expFunc(hook, result)
}
+290
View File
@@ -0,0 +1,290 @@
package keeper_test
import (
"encoding/json"
"math/big"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/cerc-io/laconicd/app"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
"github.com/cerc-io/laconicd/encoding"
"github.com/cerc-io/laconicd/tests"
"github.com/cerc-io/laconicd/testutil"
"github.com/cerc-io/laconicd/x/feemarket/types"
"github.com/cosmos/cosmos-sdk/baseapp"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
"github.com/cosmos/cosmos-sdk/simapp"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
)
var _ = Describe("Feemarket", func() {
var privKey *ethsecp256k1.PrivKey
Describe("Performing EVM transactions", func() {
type txParams struct {
gasLimit uint64
gasPrice *big.Int
gasFeeCap *big.Int
gasTipCap *big.Int
accesses *ethtypes.AccessList
}
type getprices func() txParams
Context("with MinGasPrices (feemarket param) < BaseFee (feemarket)", func() {
var (
baseFee int64
minGasPrices int64
)
BeforeEach(func() {
baseFee = 10_000_000_000
minGasPrices = baseFee - 5_000_000_000
// Note that the tests run the same transactions with `gasLimit =
// 100_000`. With the fee calculation `Fee = (baseFee + tip) * gasLimit`,
// a `minGasPrices = 5_000_000_000` results in `minGlobalFee =
// 500_000_000_000_000`
privKey, _ = setupTestWithContext("1", sdk.NewDec(minGasPrices), sdk.NewInt(baseFee))
})
Context("during CheckTx", func() {
DescribeTable("should accept transactions with gas Limit > 0",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasLimit, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := checkEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{100000, big.NewInt(baseFee), nil, nil, nil}
}),
Entry("dynamic tx", func() txParams {
return txParams{100000, nil, big.NewInt(baseFee), big.NewInt(0), &ethtypes.AccessList{}}
}),
)
DescribeTable("should not accept transactions with gas Limit > 0",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasLimit, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := checkEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(false), "transaction should have succeeded", res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{0, big.NewInt(baseFee), nil, nil, nil}
}),
Entry("dynamic tx", func() txParams {
return txParams{0, nil, big.NewInt(baseFee), big.NewInt(0), &ethtypes.AccessList{}}
}),
)
})
Context("during DeliverTx", func() {
DescribeTable("should accept transactions with gas Limit > 0",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasLimit, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := deliverEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{100000, big.NewInt(baseFee), nil, nil, nil}
}),
Entry("dynamic tx", func() txParams {
return txParams{100000, nil, big.NewInt(baseFee), big.NewInt(0), &ethtypes.AccessList{}}
}),
)
DescribeTable("should not accept transactions with gas Limit > 0",
func(malleate getprices) {
p := malleate()
to := tests.GenerateAddress()
msgEthereumTx := buildEthTx(privKey, &to, p.gasLimit, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
res := checkEthTx(privKey, msgEthereumTx)
Expect(res.IsOK()).To(Equal(false), "transaction should have succeeded", res.GetLog())
},
Entry("legacy tx", func() txParams {
return txParams{0, big.NewInt(baseFee), nil, nil, nil}
}),
Entry("dynamic tx", func() txParams {
return txParams{0, nil, big.NewInt(baseFee), big.NewInt(0), &ethtypes.AccessList{}}
}),
)
})
})
})
})
// setupTestWithContext sets up a test chain with an example Cosmos send msg,
// given a local (validator config) and a gloabl (feemarket param) minGasPrice
func setupTestWithContext(valMinGasPrice string, minGasPrice sdk.Dec, baseFee sdk.Int) (*ethsecp256k1.PrivKey, banktypes.MsgSend) {
privKey, msg := setupTest(valMinGasPrice + s.denom)
params := types.DefaultParams()
params.MinGasPrice = minGasPrice
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
s.app.FeeMarketKeeper.SetBaseFee(s.ctx, baseFee.BigInt())
s.Commit()
return privKey, msg
}
func setupTest(localMinGasPrices string) (*ethsecp256k1.PrivKey, banktypes.MsgSend) {
setupChain(localMinGasPrices)
privKey, address := generateKey()
amount, ok := sdk.NewIntFromString("10000000000000000000")
s.Require().True(ok)
initBalance := sdk.Coins{sdk.Coin{
Denom: s.denom,
Amount: amount,
}}
testutil.FundAccount(s.app.BankKeeper, s.ctx, address, initBalance)
msg := banktypes.MsgSend{
FromAddress: address.String(),
ToAddress: address.String(),
Amount: sdk.Coins{sdk.Coin{
Denom: s.denom,
Amount: sdk.NewInt(10000),
}},
}
s.Commit()
return privKey, msg
}
func setupChain(localMinGasPricesStr string) {
// Initialize the app, so we can use SetMinGasPrices to set the
// validator-specific min-gas-prices setting
db := dbm.NewMemDB()
newapp := app.NewEthermintApp(
log.NewNopLogger(),
db,
nil,
true,
map[int64]bool{},
app.DefaultNodeHome,
5,
encoding.MakeConfig(app.ModuleBasics),
simapp.EmptyAppOptions{},
baseapp.SetMinGasPrices(localMinGasPricesStr),
)
genesisState := app.NewTestGenesisState(newapp.AppCodec())
genesisState[types.ModuleName] = newapp.AppCodec().MustMarshalJSON(types.DefaultGenesisState())
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
s.Require().NoError(err)
// Initialize the chain
newapp.InitChain(
abci.RequestInitChain{
ChainId: "ethermint_9000-1",
Validators: []abci.ValidatorUpdate{},
AppStateBytes: stateBytes,
ConsensusParams: app.DefaultConsensusParams,
},
)
s.app = newapp
s.SetupApp(false)
}
func generateKey() (*ethsecp256k1.PrivKey, sdk.AccAddress) {
address, priv := tests.NewAddrKey()
return priv.(*ethsecp256k1.PrivKey), sdk.AccAddress(address.Bytes())
}
func getNonce(addressBytes []byte) uint64 {
return s.app.EvmKeeper.GetNonce(
s.ctx,
common.BytesToAddress(addressBytes),
)
}
func buildEthTx(
priv *ethsecp256k1.PrivKey,
to *common.Address,
gasLimit uint64,
gasPrice *big.Int,
gasFeeCap *big.Int,
gasTipCap *big.Int,
accesses *ethtypes.AccessList,
) *evmtypes.MsgEthereumTx {
chainID := s.app.EvmKeeper.ChainID()
from := common.BytesToAddress(priv.PubKey().Address().Bytes())
nonce := getNonce(from.Bytes())
data := make([]byte, 0)
msgEthereumTx := evmtypes.NewTx(
chainID,
nonce,
to,
nil,
gasLimit,
gasPrice,
gasFeeCap,
gasTipCap,
data,
accesses,
)
msgEthereumTx.From = from.String()
return msgEthereumTx
}
func prepareEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) []byte {
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
option, err := codectypes.NewAnyWithValue(&evmtypes.ExtensionOptionsEthereumTx{})
s.Require().NoError(err)
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
s.Require().True(ok)
builder.SetExtensionOptions(option)
err = msgEthereumTx.Sign(s.ethSigner, tests.NewSigner(priv))
s.Require().NoError(err)
// A valid msg should have empty `From`
msgEthereumTx.From = ""
err = txBuilder.SetMsgs(msgEthereumTx)
s.Require().NoError(err)
txData, err := evmtypes.UnpackTxData(msgEthereumTx.Data)
s.Require().NoError(err)
evmDenom := s.app.EvmKeeper.GetParams(s.ctx).EvmDenom
fees := sdk.Coins{{Denom: evmDenom, Amount: sdk.NewIntFromBigInt(txData.Fee())}}
builder.SetFeeAmount(fees)
builder.SetGasLimit(msgEthereumTx.GetGas())
// bz are bytes to be broadcasted over the network
bz, err := encodingConfig.TxConfig.TxEncoder()(txBuilder.GetTx())
s.Require().NoError(err)
return bz
}
func checkEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) abci.ResponseCheckTx {
bz := prepareEthTx(priv, msgEthereumTx)
req := abci.RequestCheckTx{Tx: bz}
res := s.app.BaseApp.CheckTx(req)
return res
}
func deliverEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) abci.ResponseDeliverTx {
bz := prepareEthTx(priv, msgEthereumTx)
req := abci.RequestDeliverTx{Tx: bz}
res := s.app.BaseApp.DeliverTx(req)
return res
}
+51 -18
View File
@@ -19,6 +19,7 @@ import (
ethermint "github.com/cerc-io/laconicd/types"
"github.com/cerc-io/laconicd/x/evm/statedb"
"github.com/cerc-io/laconicd/x/evm/types"
evm "github.com/cerc-io/laconicd/x/evm/vm"
)
// Keeper grants access to the EVM module state and implements the go-ethereum StateDB interface.
@@ -54,14 +55,25 @@ type Keeper struct {
// EVM Hooks for tx post-processing
hooks types.EvmHooks
// custom stateless precompiled smart contracts
customPrecompiles evm.PrecompiledContracts
// evm constructor function
evmConstructor evm.Constructor
}
// NewKeeper generates new evm module keeper
func NewKeeper(
cdc codec.BinaryCodec,
storeKey, transientKey storetypes.StoreKey, paramSpace paramtypes.Subspace,
ak types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper,
storeKey, transientKey storetypes.StoreKey,
paramSpace paramtypes.Subspace,
ak types.AccountKeeper,
bankKeeper types.BankKeeper,
sk types.StakingKeeper,
fmk types.FeeMarketKeeper,
customPrecompiles evm.PrecompiledContracts,
evmConstructor evm.Constructor,
tracer string,
) *Keeper {
// ensure evm module account is set
@@ -76,15 +88,17 @@ func NewKeeper(
// NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations
return &Keeper{
cdc: cdc,
paramSpace: paramSpace,
accountKeeper: ak,
bankKeeper: bankKeeper,
stakingKeeper: sk,
feeMarketKeeper: fmk,
storeKey: storeKey,
transientKey: transientKey,
tracer: tracer,
cdc: cdc,
paramSpace: paramSpace,
accountKeeper: ak,
bankKeeper: bankKeeper,
stakingKeeper: sk,
feeMarketKeeper: fmk,
storeKey: storeKey,
transientKey: transientKey,
customPrecompiles: customPrecompiles,
evmConstructor: evmConstructor,
tracer: tracer,
}
}
@@ -222,11 +236,11 @@ func (k *Keeper) SetHooks(eh types.EvmHooks) *Keeper {
}
// PostTxProcessing delegate the call to the hooks. If no hook has been registered, this function returns with a `nil` error
func (k *Keeper) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
func (k *Keeper) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
if k.hooks == nil {
return nil
}
return k.hooks.PostTxProcessing(ctx, from, to, receipt)
return k.hooks.PostTxProcessing(ctx, msg, receipt)
}
// Tracer return a default vm.Tracer based on current keeper state
@@ -283,17 +297,26 @@ func (k *Keeper) GetNonce(ctx sdk.Context, addr common.Address) uint64 {
// GetBalance load account's balance of gas token
func (k *Keeper) GetBalance(ctx sdk.Context, addr common.Address) *big.Int {
cosmosAddr := sdk.AccAddress(addr.Bytes())
params := k.GetParams(ctx)
coin := k.bankKeeper.GetBalance(ctx, cosmosAddr, params.EvmDenom)
evmDenom := ""
k.paramSpace.GetIfExists(ctx, types.ParamStoreKeyEVMDenom, &evmDenom)
// if node is pruned, params is empty. Return invalid value
if evmDenom == "" {
return big.NewInt(-1)
}
coin := k.bankKeeper.GetBalance(ctx, cosmosAddr, evmDenom)
return coin.Amount.BigInt()
}
// BaseFee returns current base fee, return values:
// GetBaseFee returns current base fee, return values:
// - `nil`: london hardfork not enabled.
// - `0`: london hardfork enabled but feemarket is not enabled.
// - `n`: both london hardfork and feemarket are enabled.
func (k Keeper) BaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int {
if !types.IsLondon(ethCfg, ctx.BlockHeight()) {
func (k Keeper) GetBaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int {
return k.getBaseFee(ctx, types.IsLondon(ethCfg, ctx.BlockHeight()))
}
func (k Keeper) getBaseFee(ctx sdk.Context, london bool) *big.Int {
if !london {
return nil
}
baseFee := k.feeMarketKeeper.GetBaseFee(ctx)
@@ -304,6 +327,16 @@ func (k Keeper) BaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int {
return baseFee
}
// GetMinGasMultiplier returns the MinGasMultiplier param from the fee market module
func (k Keeper) GetMinGasMultiplier(ctx sdk.Context) sdk.Dec {
fmkParmas := k.feeMarketKeeper.GetParams(ctx)
if fmkParmas.MinGasMultiplier.IsNil() {
// in case we are executing eth_call on a legacy block, returns a zero value.
return sdk.ZeroDec()
}
return fmkParmas.MinGasMultiplier
}
// ResetTransientGasUsed reset gas used to prepare for execution of current cosmos tx, called in ante handler.
func (k Keeper) ResetTransientGasUsed(ctx sdk.Context) {
store := ctx.TransientStore(k.transientKey)
+67 -28
View File
@@ -8,8 +8,10 @@ import (
"testing"
"time"
cmath "cosmossdk.io/math"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
sdkmath "cosmossdk.io/math"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
@@ -21,8 +23,9 @@ import (
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/bank/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
tmjson "github.com/tendermint/tendermint/libs/json"
"github.com/cerc-io/laconicd/app"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
@@ -32,6 +35,7 @@ import (
ethermint "github.com/cerc-io/laconicd/types"
"github.com/cerc-io/laconicd/x/evm/statedb"
"github.com/cerc-io/laconicd/x/evm/types"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -46,7 +50,7 @@ import (
"github.com/tendermint/tendermint/version"
)
var testTokens = cmath.NewIntWithDecimal(1000, 18)
var testTokens = sdkmath.NewIntWithDecimal(1000, 18)
type KeeperTestSuite struct {
suite.Suite
@@ -67,12 +71,31 @@ type KeeperTestSuite struct {
enableFeemarket bool
enableLondonHF bool
mintFeeCollector bool
denom string
}
/// DoSetupTest setup test environment, it uses`require.TestingT` to support both `testing.T` and `testing.B`.
func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
checkTx := false
var s *KeeperTestSuite
func TestKeeperTestSuite(t *testing.T) {
s = new(KeeperTestSuite)
s.enableFeemarket = false
s.enableLondonHF = true
suite.Run(t, s)
// Run Ginkgo integration tests
RegisterFailHandler(Fail)
RunSpecs(t, "Keeper Suite")
}
func (suite *KeeperTestSuite) SetupTest() {
checkTx := false
suite.app = app.Setup(checkTx, nil)
suite.SetupApp(checkTx)
}
// SetupApp setup test environment, it uses`require.TestingT` to support both `testing.T` and `testing.B`.
func (suite *KeeperTestSuite) SetupApp(checkTx bool) {
t := suite.T()
// account key, use a constant account to keep unit test deterministic.
ecdsaPriv, err := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
require.NoError(t, err)
@@ -87,7 +110,7 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
require.NoError(t, err)
suite.consAddress = sdk.ConsAddress(priv.PubKey().Address())
suite.app = app.Setup(suite.T(), checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
suite.app = app.Setup(checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
feemarketGenesis := feemarkettypes.DefaultGenesisState()
if suite.enableFeemarket {
feemarketGenesis.Params.EnableHeight = 1
@@ -98,15 +121,48 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
genesis[feemarkettypes.ModuleName] = app.AppCodec().MustMarshalJSON(feemarketGenesis)
if !suite.enableLondonHF {
evmGenesis := types.DefaultGenesisState()
maxInt := sdk.NewInt(math.MaxInt64)
maxInt := sdkmath.NewInt(math.MaxInt64)
evmGenesis.Params.ChainConfig.LondonBlock = &maxInt
evmGenesis.Params.ChainConfig.ArrowGlacierBlock = &maxInt
evmGenesis.Params.ChainConfig.MergeForkBlock = &maxInt
evmGenesis.Params.ChainConfig.GrayGlacierBlock = &maxInt
evmGenesis.Params.ChainConfig.MergeNetsplitBlock = &maxInt
genesis[types.ModuleName] = app.AppCodec().MustMarshalJSON(evmGenesis)
}
return genesis
})
if suite.mintFeeCollector {
// mint some coin to fee collector
coins := sdk.NewCoins(sdk.NewCoin(types.DefaultEVMDenom, sdkmath.NewInt(int64(params.TxGas)-1)))
genesisState := app.NewTestGenesisState(suite.app.AppCodec())
balances := []banktypes.Balance{
{
Address: suite.app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName).String(),
Coins: coins,
},
}
var bankGenesis banktypes.GenesisState
suite.app.AppCodec().MustUnmarshalJSON(genesisState[banktypes.ModuleName], &bankGenesis)
// Update balances and total supply
bankGenesis.Balances = append(bankGenesis.Balances, balances...)
bankGenesis.Supply = bankGenesis.Supply.Add(coins...)
genesisState[banktypes.ModuleName] = suite.app.AppCodec().MustMarshalJSON(&bankGenesis)
// we marshal the genesisState of all module to a byte array
stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)
// Initialize the chain
suite.app.InitChain(
abci.RequestInitChain{
ChainId: "ethermint_9000-1",
Validators: []abci.ValidatorUpdate{},
ConsensusParams: app.DefaultConsensusParams,
AppStateBytes: stateBytes,
},
)
}
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{
Height: 1,
ChainID: "ethermint_9000-1",
@@ -131,12 +187,6 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
LastResultsHash: tmhash.Sum([]byte("last_result")),
})
if suite.mintFeeCollector {
// mint some coin to fee collector
coins := sdk.NewCoins(sdk.NewCoin(types.DefaultEVMDenom, sdk.NewInt(int64(params.TxGas)-1)))
testutil.FundModuleAccount(suite.app.BankKeeper, suite.ctx, authtypes.FeeCollectorName, coins)
}
queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, suite.app.EvmKeeper)
suite.queryClient = types.NewQueryClient(queryHelper)
@@ -150,7 +200,6 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
valAddr := sdk.ValAddress(suite.address.Bytes())
validator, err := stakingtypes.NewValidator(valAddr, priv.PubKey(), stakingtypes.Description{})
require.NoError(t, err)
err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator)
require.NoError(t, err)
err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator)
@@ -161,10 +210,7 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig)
suite.ethSigner = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
suite.appCodec = encodingConfig.Codec
}
func (suite *KeeperTestSuite) SetupTest() {
suite.DoSetupTest(suite.T())
suite.denom = evmtypes.DefaultEVMDenom
}
func (suite *KeeperTestSuite) EvmDenom() string {
@@ -381,17 +427,10 @@ func (suite *KeeperTestSuite) TestBaseFee() {
suite.app.EvmKeeper.BeginBlock(suite.ctx, abci.RequestBeginBlock{})
params := suite.app.EvmKeeper.GetParams(suite.ctx)
ethCfg := params.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID())
baseFee := suite.app.EvmKeeper.BaseFee(suite.ctx, ethCfg)
baseFee := suite.app.EvmKeeper.GetBaseFee(suite.ctx, ethCfg)
suite.Require().Equal(tc.expectBaseFee, baseFee)
})
}
suite.enableFeemarket = false
suite.enableLondonHF = true
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, &KeeperTestSuite{
enableFeemarket: false,
enableLondonHF: true,
})
}
+16
View File
@@ -1,5 +1,11 @@
package keeper
import (
v2 "github.com/cerc-io/laconicd/x/evm/migrations/v2"
v3 "github.com/cerc-io/laconicd/x/evm/migrations/v3"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Migrator is a struct for handling in-place store migrations.
type Migrator struct {
keeper Keeper
@@ -11,3 +17,13 @@ func NewMigrator(keeper Keeper) Migrator {
keeper: keeper,
}
}
// Migrate1to2 migrates the store from consensus version v1 to v2
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return v2.MigrateStore(ctx, &m.keeper.paramSpace)
}
// Migrate2to3 migrates the store from consensus version v2 to v3
func (m Migrator) Migrate2to3(ctx sdk.Context) error {
return v3.MigrateStore(ctx, &m.keeper.paramSpace)
}
+45 -1
View File
@@ -9,6 +9,8 @@ import (
tmbytes "github.com/tendermint/tendermint/libs/bytes"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/armon/go-metrics"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -19,7 +21,8 @@ var _ types.MsgServer = &Keeper{}
// EthereumTx implements the gRPC MsgServer interface. It receives a transaction which is then
// executed (i.e applied) against the go-ethereum EVM. The provided SDK Context is set to the Keeper
// so that it can call the StateDB methods without receiving it as a function parameter.
// so that it can implements and call the StateDB methods without receiving it as a function
// parameter.
func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*types.MsgEthereumTxResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
@@ -27,11 +30,52 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t
tx := msg.AsTransaction()
txIndex := k.GetTxIndexTransient(ctx)
labels := []metrics.Label{
telemetry.NewLabel("tx_type", fmt.Sprintf("%d", tx.Type())),
telemetry.NewLabel("from", sender),
}
if tx.To() == nil {
labels = []metrics.Label{telemetry.NewLabel("execution", "create")}
} else {
labels = []metrics.Label{
telemetry.NewLabel("execution", "call"),
telemetry.NewLabel("to", tx.To().Hex()), // recipient address (contract or account)
}
}
response, err := k.ApplyTransaction(ctx, tx)
if err != nil {
return nil, sdkerrors.Wrap(err, "failed to apply transaction")
}
defer func() {
telemetry.IncrCounterWithLabels(
[]string{"tx", "msg", "ethereum_tx", "total"},
1,
labels,
)
if response.GasUsed != 0 {
telemetry.IncrCounterWithLabels(
[]string{"tx", "msg", "ethereum_tx", "gas_used", "total"},
float32(response.GasUsed),
labels,
)
// Observe which users define a gas limit >> gas used. Note, that
// gas_limit and gas_used are always > 0
gasLimit := sdk.NewDec(int64(tx.Gas()))
gasRatio, err := gasLimit.QuoInt64(int64(response.GasUsed)).Float64()
if err == nil {
telemetry.SetGaugeWithLabels(
[]string{"tx", "msg", "ethereum_tx", "gas_limit", "per", "gas_used"},
float32(gasRatio),
labels,
)
}
}
}()
attrs := []sdk.Attribute{
sdk.NewAttribute(sdk.AttributeKeyAmount, tx.Value().String()),
// add event for ethereum transaction hash format
+6 -1
View File
@@ -8,7 +8,12 @@ import (
// GetParams returns the total set of evm parameters.
func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
k.paramSpace.GetParamSet(ctx, &params)
// TODO: update once https://github.com/cosmos/cosmos-sdk/pull/12615 is merged
// and released
for _, pair := range params.ParamSetPairs() {
k.paramSpace.GetIfExists(ctx, pair.Key, pair.Value)
}
return params
}
+91 -55
View File
@@ -4,6 +4,8 @@ import (
"math"
"math/big"
sdkmath "cosmossdk.io/math"
tmtypes "github.com/tendermint/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -14,6 +16,7 @@ import (
ethermint "github.com/cerc-io/laconicd/types"
"github.com/cerc-io/laconicd/x/evm/statedb"
"github.com/cerc-io/laconicd/x/evm/types"
evm "github.com/cerc-io/laconicd/x/evm/vm"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
@@ -46,7 +49,7 @@ func (k *Keeper) EVMConfig(ctx sdk.Context) (*types.EVMConfig, error) {
return nil, sdkerrors.Wrap(err, "failed to obtain coinbase address")
}
baseFee := k.BaseFee(ctx, ethCfg)
baseFee := k.GetBaseFee(ctx, ethCfg)
return &types.EVMConfig{
Params: params,
ChainConfig: ethCfg,
@@ -55,7 +58,7 @@ func (k *Keeper) EVMConfig(ctx sdk.Context) (*types.EVMConfig, error) {
}, nil
}
// TxConfig load `TxConfig` from current transient storage
// TxConfig loads `TxConfig` from current transient storage
func (k *Keeper) TxConfig(ctx sdk.Context, txHash common.Hash) statedb.TxConfig {
return statedb.NewTxConfig(
common.BytesToHash(ctx.HeaderHash()), // BlockHash
@@ -75,7 +78,7 @@ func (k *Keeper) NewEVM(
cfg *types.EVMConfig,
tracer vm.EVMLogger,
stateDB vm.StateDB,
) *vm.EVM {
) evm.EVM {
blockCtx := vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
@@ -93,7 +96,7 @@ func (k *Keeper) NewEVM(
tracer = k.Tracer(ctx, msg, cfg.ChainConfig)
}
vmConfig := k.VMConfig(ctx, msg, cfg, tracer)
return vm.NewEVM(blockCtx, txCtx, stateDB, cfg.ChainConfig, vmConfig)
return k.evmConstructor(blockCtx, txCtx, stateDB, cfg.ChainConfig, vmConfig, k.customPrecompiles)
}
// VMConfig creates an EVM configuration from the debug setting and the extra EIPs enabled on the
@@ -176,7 +179,7 @@ func (k Keeper) GetHashFn(ctx sdk.Context) vm.GetHashFunc {
// ApplyTransaction runs and attempts to perform a state transition with the given transaction (i.e Message), that will
// only be persisted (committed) to the underlying KVStore if the transaction does not fail.
//
// Gas tracking
// # Gas tracking
//
// Ethereum consumes gas according to the EVM opcodes instead of general reads and writes to store. Because of this, the
// state transition needs to ignore the SDK gas consumption mechanism defined by the GasKVStore and instead consume the
@@ -235,42 +238,47 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t
bloomReceipt = ethtypes.BytesToBloom(bloom.Bytes())
}
cumulativeGasUsed := res.GasUsed
if ctx.BlockGasMeter() != nil {
limit := ctx.BlockGasMeter().Limit()
consumed := ctx.BlockGasMeter().GasConsumed()
cumulativeGasUsed = uint64(math.Min(float64(cumulativeGasUsed+consumed), float64(limit)))
}
var contractAddr common.Address
if msg.To() == nil {
contractAddr = crypto.CreateAddress(msg.From(), msg.Nonce())
}
receipt := &ethtypes.Receipt{
Type: tx.Type(),
PostState: nil, // TODO: intermediate state root
CumulativeGasUsed: cumulativeGasUsed,
Bloom: bloomReceipt,
Logs: logs,
TxHash: txConfig.TxHash,
ContractAddress: contractAddr,
GasUsed: res.GasUsed,
BlockHash: txConfig.BlockHash,
BlockNumber: big.NewInt(ctx.BlockHeight()),
TransactionIndex: txConfig.TxIndex,
}
if !res.Failed() {
cumulativeGasUsed := res.GasUsed
if ctx.BlockGasMeter() != nil {
limit := ctx.BlockGasMeter().Limit()
consumed := ctx.BlockGasMeter().GasConsumed()
cumulativeGasUsed = uint64(math.Min(float64(cumulativeGasUsed+consumed), float64(limit)))
}
var contractAddr common.Address
if msg.To() == nil {
contractAddr = crypto.CreateAddress(msg.From(), msg.Nonce())
}
receipt := &ethtypes.Receipt{
Type: tx.Type(),
PostState: nil, // TODO: intermediate state root
Status: ethtypes.ReceiptStatusSuccessful,
CumulativeGasUsed: cumulativeGasUsed,
Bloom: bloomReceipt,
Logs: logs,
TxHash: txConfig.TxHash,
ContractAddress: contractAddr,
GasUsed: res.GasUsed,
BlockHash: txConfig.BlockHash,
BlockNumber: big.NewInt(ctx.BlockHeight()),
TransactionIndex: txConfig.TxIndex,
}
receipt.Status = ethtypes.ReceiptStatusSuccessful
// Only call hooks if tx executed successfully.
if err = k.PostTxProcessing(tmpCtx, msg.From(), tx.To(), receipt); err != nil {
if err = k.PostTxProcessing(tmpCtx, msg, receipt); err != nil {
// If hooks return error, revert the whole tx.
res.VmError = types.ErrPostTxProcessing.Error()
k.Logger(ctx).Error("tx post processing failed", "error", err)
// If the tx failed in post processing hooks, we should clear the logs
res.Logs = nil
} else if commit != nil {
// PostTxProcessing is successful, commit the tmpCtx
commit()
// Since the post processing can alter the log, we need to update the result
res.Logs = types.NewLogsFromEth(receipt.Logs)
ctx.EventManager().EmitEvents(tmpCtx.EventManager().Events())
}
}
@@ -280,11 +288,10 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t
return nil, sdkerrors.Wrapf(err, "failed to refund gas leftover gas to sender %s", msg.From())
}
if len(logs) > 0 {
if len(receipt.Logs) > 0 {
// Update transient block bloom filter
k.SetBlockBloomTransient(ctx, bloom)
k.SetLogSizeTransient(ctx, uint64(txConfig.LogIndex)+uint64(len(logs)))
k.SetBlockBloomTransient(ctx, receipt.Bloom.Big())
k.SetLogSizeTransient(ctx, uint64(txConfig.LogIndex)+uint64(len(receipt.Logs)))
}
k.SetTxIndexTransient(ctx, uint64(txConfig.TxIndex)+1)
@@ -303,18 +310,18 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t
// If the message fails, the VM execution error with the reason will be returned to the client
// and the transaction won't be committed to the store.
//
// Reverted state
// # Reverted state
//
// The snapshot and rollback are supported by the `statedb.StateDB`.
//
// Different Callers
// # Different Callers
//
// It's called in three scenarios:
// 1. `ApplyTransaction`, in the transaction processing flow.
// 2. `EthCall/EthEstimateGas` grpc query handler.
// 3. Called by other native modules directly.
//
// Prechecks and Preprocessing
// # Prechecks and Preprocessing
//
// All relevant state transition prechecks for the MsgEthereumTx are performed on the AnteHandler,
// prior to running the transaction against the state. The prechecks run are the following:
@@ -330,14 +337,20 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t
//
// 1. set up the initial access list (iff fork > Berlin)
//
// Tracer parameter
// # Tracer parameter
//
// It should be a `vm.Tracer` object or nil, if pass `nil`, it'll create a default one based on keeper options.
//
// Commit parameter
// # Commit parameter
//
// If commit is true, the `StateDB` will be committed, otherwise discarded.
func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, msg core.Message, tracer vm.EVMLogger, commit bool, cfg *types.EVMConfig, txConfig statedb.TxConfig) (*types.MsgEthereumTxResponse, error) {
func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context,
msg core.Message,
tracer vm.EVMLogger,
commit bool,
cfg *types.EVMConfig,
txConfig statedb.TxConfig,
) (*types.MsgEthereumTxResponse, error) {
var (
ret []byte // return bytes from evm execution
vmErr error // vm errors do not effect consensus and are therefore not assigned to err
@@ -353,26 +366,38 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, msg core.Message, trace
stateDB := statedb.New(ctx, k, txConfig)
evm := k.NewEVM(ctx, msg, cfg, tracer, stateDB)
leftoverGas := msg.Gas()
// Allow the tracer captures the tx level events, mainly the gas consumption.
vmCfg := evm.Config()
if vmCfg.Debug {
vmCfg.Tracer.CaptureTxStart(leftoverGas)
defer func() {
vmCfg.Tracer.CaptureTxEnd(leftoverGas)
}()
}
sender := vm.AccountRef(msg.From())
contractCreation := msg.To() == nil
isLondon := cfg.ChainConfig.IsLondon(evm.Context.BlockNumber)
isLondon := cfg.ChainConfig.IsLondon(evm.Context().BlockNumber)
intrinsicGas, err := k.GetEthIntrinsicGas(ctx, msg, cfg.ChainConfig, contractCreation)
if err != nil {
// should have already been checked on Ante Handler
return nil, sdkerrors.Wrap(err, "intrinsic gas failed")
}
// Should check again even if it is checked on Ante Handler, because eth_call don't go through Ante Handler.
if msg.Gas() < intrinsicGas {
if leftoverGas < intrinsicGas {
// eth_estimateGas will check for this exact error
return nil, sdkerrors.Wrap(core.ErrIntrinsicGas, "apply message")
}
leftoverGas := msg.Gas() - intrinsicGas
leftoverGas -= intrinsicGas
// access list preparation is moved from ante handler to here, because it's needed when `ApplyMessage` is called
// under contexts where ante handlers are not run, for example `eth_call` and `eth_estimateGas`.
if rules := cfg.ChainConfig.Rules(big.NewInt(ctx.BlockHeight()), cfg.ChainConfig.MergeForkBlock != nil); rules.IsBerlin {
stateDB.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
if rules := cfg.ChainConfig.Rules(big.NewInt(ctx.BlockHeight()), cfg.ChainConfig.MergeNetsplitBlock != nil); rules.IsBerlin {
stateDB.PrepareAccessList(msg.From(), msg.To(), evm.ActivePrecompiles(rules), msg.AccessList())
}
if contractCreation {
@@ -397,12 +422,8 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, msg core.Message, trace
if msg.Gas() < leftoverGas {
return nil, sdkerrors.Wrap(types.ErrGasOverflow, "apply message")
}
gasUsed := msg.Gas() - leftoverGas
refund := GasToRefund(stateDB.GetRefund(), gasUsed, refundQuotient)
if refund > gasUsed {
return nil, sdkerrors.Wrap(types.ErrGasOverflow, "apply message")
}
gasUsed -= refund
// refund gas
leftoverGas += GasToRefund(stateDB.GetRefund(), msg.Gas()-leftoverGas, refundQuotient)
// EVM execution error needs to be available for the JSON-RPC client
var vmError string
@@ -417,6 +438,21 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, msg core.Message, trace
}
}
// calculate a minimum amount of gas to be charged to sender if GasLimit
// is considerably higher than GasUsed to stay more aligned with Tendermint gas mechanics
// for more info https://github.com/cerc-io/laconicd/issues/1085
gasLimit := sdk.NewDec(int64(msg.Gas()))
minGasMultiplier := k.GetMinGasMultiplier(ctx)
minimumGasUsed := gasLimit.Mul(minGasMultiplier)
if msg.Gas() < leftoverGas {
return nil, sdkerrors.Wrapf(types.ErrGasOverflow, "message gas limit < leftover gas (%d < %d)", msg.Gas(), leftoverGas)
}
temporaryGasUsed := msg.Gas() - leftoverGas
gasUsed := sdk.MaxDec(minimumGasUsed, sdk.NewDec(int64(temporaryGasUsed))).TruncateInt().Uint64()
// reset leftoverGas, to be used by the tracer
leftoverGas = msg.Gas() - gasUsed
return &types.MsgEthereumTxResponse{
GasUsed: gasUsed,
VmError: vmError,
@@ -459,7 +495,7 @@ func (k *Keeper) RefundGas(ctx sdk.Context, msg core.Message, leftoverGas uint64
return sdkerrors.Wrapf(types.ErrInvalidRefund, "refunded amount value cannot be negative %d", remaining.Int64())
case 1:
// positive amount refund
refundedCoins := sdk.Coins{sdk.NewCoin(denom, sdk.NewIntFromBigInt(remaining))}
refundedCoins := sdk.Coins{sdk.NewCoin(denom, sdkmath.NewIntFromBigInt(remaining))}
// refund to sender from the fee collector module account, which is the escrow account in charge of collecting tx fees
@@ -143,7 +143,7 @@ func newNativeMessage(
func BenchmarkApplyTransaction(b *testing.B) {
suite := KeeperTestSuite{enableLondonHF: true}
suite.DoSetupTest(b)
suite.SetupTest()
ethSigner := ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
@@ -170,7 +170,7 @@ func BenchmarkApplyTransaction(b *testing.B) {
func BenchmarkApplyTransactionWithLegacyTx(b *testing.B) {
suite := KeeperTestSuite{enableLondonHF: true}
suite.DoSetupTest(b)
suite.SetupTest()
ethSigner := ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
@@ -197,7 +197,7 @@ func BenchmarkApplyTransactionWithLegacyTx(b *testing.B) {
func BenchmarkApplyTransactionWithDynamicFeeTx(b *testing.B) {
suite := KeeperTestSuite{enableFeemarket: true, enableLondonHF: true}
suite.DoSetupTest(b)
suite.SetupTest()
ethSigner := ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
@@ -224,7 +224,7 @@ func BenchmarkApplyTransactionWithDynamicFeeTx(b *testing.B) {
func BenchmarkApplyMessage(b *testing.B) {
suite := KeeperTestSuite{enableLondonHF: true}
suite.DoSetupTest(b)
suite.SetupTest()
params := suite.app.EvmKeeper.GetParams(suite.ctx)
ethCfg := params.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID())
@@ -259,7 +259,7 @@ func BenchmarkApplyMessage(b *testing.B) {
func BenchmarkApplyMessageWithLegacyTx(b *testing.B) {
suite := KeeperTestSuite{enableLondonHF: true}
suite.DoSetupTest(b)
suite.SetupTest()
params := suite.app.EvmKeeper.GetParams(suite.ctx)
ethCfg := params.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID())
@@ -294,7 +294,7 @@ func BenchmarkApplyMessageWithLegacyTx(b *testing.B) {
func BenchmarkApplyMessageWithDynamicFeeTx(b *testing.B) {
suite := KeeperTestSuite{enableFeemarket: true, enableLondonHF: true}
suite.DoSetupTest(b)
suite.SetupTest()
params := suite.app.EvmKeeper.GetParams(suite.ctx)
ethCfg := params.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID())
-10
View File
@@ -206,16 +206,6 @@ func (suite *KeeperTestSuite) TestGetEthIntrinsicGas() {
true,
params.TxGas + params.TxDataNonZeroGasFrontier*1,
},
// we are not able to test the ErrGasUintOverflow due to RAM limitation
// {
// "with big data size overflow",
// make([]byte, 271300000000000000),
// nil,
// 1,
// false,
// false,
// 0,
// },
{
"no data, one accesslist, not contract creation, not homestead, not istanbul",
nil,
+5 -10
View File
@@ -1,10 +1,11 @@
package keeper
import (
"bytes"
"fmt"
"math/big"
sdkmath "cosmossdk.io/math"
ethermint "github.com/cerc-io/laconicd/types"
"github.com/cerc-io/laconicd/x/evm/statedb"
"github.com/cerc-io/laconicd/x/evm/types"
@@ -79,7 +80,7 @@ func (k *Keeper) SetBalance(ctx sdk.Context, addr common.Address, amount *big.In
switch delta.Sign() {
case 1:
// mint
coins := sdk.NewCoins(sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(delta)))
coins := sdk.NewCoins(sdk.NewCoin(params.EvmDenom, sdkmath.NewIntFromBigInt(delta)))
if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil {
return err
}
@@ -88,7 +89,7 @@ func (k *Keeper) SetBalance(ctx sdk.Context, addr common.Address, amount *big.In
}
case -1:
// burn
coins := sdk.NewCoins(sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(new(big.Int).Neg(delta))))
coins := sdk.NewCoins(sdk.NewCoin(params.EvmDenom, sdkmath.NewIntFromBigInt(new(big.Int).Neg(delta))))
if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, cosmosAddr, types.ModuleName, coins); err != nil {
return err
}
@@ -186,7 +187,7 @@ func (k *Keeper) DeleteAccount(ctx sdk.Context, addr common.Address) error {
}
// NOTE: only Ethereum accounts (contracts) can be selfdestructed
ethAcct, ok := acct.(ethermint.EthAccountI)
_, ok := acct.(ethermint.EthAccountI)
if !ok {
return sdkerrors.Wrapf(types.ErrInvalidAccount, "type %T, address %s", acct, addr)
}
@@ -196,12 +197,6 @@ func (k *Keeper) DeleteAccount(ctx sdk.Context, addr common.Address) error {
return err
}
// remove code
codeHashBz := ethAcct.GetCodeHash().Bytes()
if !bytes.Equal(codeHashBz, types.EmptyCodeHash) {
k.SetCode(ctx, codeHashBz, nil)
}
// clear storage
k.ForEachStorage(ctx, addr, func(key, _ common.Hash) bool {
k.SetState(ctx, addr, key, nil)
+11 -11
View File
@@ -15,7 +15,7 @@ import (
func BenchmarkCreateAccountNew(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
b.ResetTimer()
@@ -31,7 +31,7 @@ func BenchmarkCreateAccountNew(b *testing.B) {
func BenchmarkCreateAccountExisting(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
b.ResetTimer()
@@ -44,7 +44,7 @@ func BenchmarkCreateAccountExisting(b *testing.B) {
func BenchmarkAddBalance(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
amt := big.NewInt(10)
@@ -59,7 +59,7 @@ func BenchmarkAddBalance(b *testing.B) {
func BenchmarkSetCode(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
hash := crypto.Keccak256Hash([]byte("code")).Bytes()
@@ -74,7 +74,7 @@ func BenchmarkSetCode(b *testing.B) {
func BenchmarkSetState(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
hash := crypto.Keccak256Hash([]byte("topic")).Bytes()
@@ -89,7 +89,7 @@ func BenchmarkSetState(b *testing.B) {
func BenchmarkAddLog(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
topic := crypto.Keccak256Hash([]byte("topic"))
@@ -116,7 +116,7 @@ func BenchmarkAddLog(b *testing.B) {
func BenchmarkSnapshot(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
b.ResetTimer()
@@ -136,7 +136,7 @@ func BenchmarkSnapshot(b *testing.B) {
func BenchmarkSubBalance(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
amt := big.NewInt(10)
@@ -151,7 +151,7 @@ func BenchmarkSubBalance(b *testing.B) {
func BenchmarkSetNonce(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
b.ResetTimer()
@@ -164,7 +164,7 @@ func BenchmarkSetNonce(b *testing.B) {
func BenchmarkAddRefund(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
b.ResetTimer()
@@ -177,7 +177,7 @@ func BenchmarkAddRefund(b *testing.B) {
func BenchmarkSuicide(b *testing.B) {
suite := KeeperTestSuite{}
suite.DoSetupTest(b)
suite.SetupTest()
vmdb := suite.StateDB()
b.ResetTimer()
+19
View File
@@ -11,6 +11,7 @@ import (
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
"github.com/cerc-io/laconicd/tests"
"github.com/cerc-io/laconicd/x/evm/statedb"
"github.com/cerc-io/laconicd/x/evm/types"
@@ -420,12 +421,26 @@ func (suite *KeeperTestSuite) TestSuicide() {
suite.Require().NoError(db.Commit())
db = suite.StateDB()
// Generate 2nd address
privkey, _ := ethsecp256k1.GenerateKey()
key, err := privkey.ToECDSA()
suite.Require().NoError(err)
addr2 := crypto.PubkeyToAddress(key.PublicKey)
// Add code and state to account 2
db.SetCode(addr2, code)
suite.Require().Equal(code, db.GetCode(addr2))
for i := 0; i < 5; i++ {
db.SetState(addr2, common.BytesToHash([]byte(fmt.Sprintf("key%d", i))), common.BytesToHash([]byte(fmt.Sprintf("value%d", i))))
}
// Call Suicide
suite.Require().Equal(true, db.Suicide(suite.address))
// Check suicided is marked
suite.Require().Equal(true, db.HasSuicided(suite.address))
// Commit state
suite.Require().NoError(db.Commit())
db = suite.StateDB()
@@ -441,6 +456,10 @@ func (suite *KeeperTestSuite) TestSuicide() {
// Check account is deleted
suite.Require().Equal(common.Hash{}, db.GetCodeHash(suite.address))
// Check code is still present in addr2 and suicided is false
suite.Require().NotNil(db.GetCode(addr2))
suite.Require().Equal(false, db.HasSuicided(addr2))
}
func (suite *KeeperTestSuite) TestExist() {
+36 -22
View File
@@ -1,12 +1,13 @@
package keeper
import (
"math"
"math/big"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
ante "github.com/cosmos/cosmos-sdk/x/auth/ante"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
@@ -15,19 +16,20 @@ import (
)
// DeductTxCostsFromUserBalance it calculates the tx costs and deducts the fees
// returns (effectiveFee, priority, error)
func (k Keeper) DeductTxCostsFromUserBalance(
ctx sdk.Context,
msgEthTx evmtypes.MsgEthereumTx,
txData evmtypes.TxData,
denom string,
homestead, istanbul, london bool,
) (sdk.Coins, error) {
) (fees sdk.Coins, priority int64, err error) {
isContractCreation := txData.GetTo() == nil
// fetch sender account from signature
signerAcc, err := ante.GetSignerAcc(ctx, k.accountKeeper, msgEthTx.GetFrom())
signerAcc, err := authante.GetSignerAcc(ctx, k.accountKeeper, msgEthTx.GetFrom())
if err != nil {
return nil, sdkerrors.Wrapf(err, "account not found for sender %s", msgEthTx.From)
return nil, 0, sdkerrors.Wrapf(err, "account not found for sender %s", msgEthTx.From)
}
gasLimit := txData.GetGas()
@@ -39,7 +41,7 @@ func (k Keeper) DeductTxCostsFromUserBalance(
intrinsicGas, err := core.IntrinsicGas(txData.GetData(), accessList, isContractCreation, homestead, istanbul)
if err != nil {
return nil, sdkerrors.Wrapf(
return nil, 0, sdkerrors.Wrapf(
err,
"failed to retrieve intrinsic gas, contract creation = %t; homestead = %t, istanbul = %t",
isContractCreation, homestead, istanbul,
@@ -48,7 +50,7 @@ func (k Keeper) DeductTxCostsFromUserBalance(
// intrinsic gas verification during CheckTx
if ctx.IsCheckTx() && gasLimit < intrinsicGas {
return nil, sdkerrors.Wrapf(
return nil, 0, sdkerrors.Wrapf(
sdkerrors.ErrOutOfGas,
"gas limit too low: %d (gas limit) < %d (intrinsic gas)", gasLimit, intrinsicGas,
)
@@ -56,39 +58,51 @@ func (k Keeper) DeductTxCostsFromUserBalance(
var feeAmt *big.Int
feeMktParams := k.feeMarketKeeper.GetParams(ctx)
if london && !feeMktParams.NoBaseFee && txData.TxType() == ethtypes.DynamicFeeTxType {
baseFee := k.feeMarketKeeper.GetBaseFee(ctx)
if txData.GetGasFeeCap().Cmp(baseFee) < 0 {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "the tx gasfeecap is lower than the tx baseFee: %s (gasfeecap), %s (basefee) ", txData.GetGasFeeCap(), baseFee)
}
feeAmt = txData.EffectiveFee(baseFee)
} else {
feeAmt = txData.Fee()
baseFee := k.getBaseFee(ctx, london)
if baseFee != nil && txData.GetGasFeeCap().Cmp(baseFee) < 0 {
return nil, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee,
"the tx gasfeecap is lower than the tx baseFee: %s (gasfeecap), %s (basefee) ",
txData.GetGasFeeCap(),
baseFee)
}
feeAmt = txData.EffectiveFee(baseFee)
if feeAmt.Sign() == 0 {
// zero fee, no need to deduct
return sdk.NewCoins(), nil
return sdk.Coins{}, 0, nil
}
fees := sdk.Coins{sdk.NewCoin(denom, sdk.NewIntFromBigInt(feeAmt))}
fees = sdk.Coins{sdk.NewCoin(denom, sdkmath.NewIntFromBigInt(feeAmt))}
// deduct the full gas cost from the user balance
if err := ante.DeductFees(k.bankKeeper, ctx, signerAcc, fees); err != nil {
return nil, sdkerrors.Wrapf(
if err := authante.DeductFees(k.bankKeeper, ctx, signerAcc, fees); err != nil {
return nil, 0, sdkerrors.Wrapf(
err,
"failed to deduct full gas cost %s from the user %s balance",
fees, msgEthTx.From,
)
}
return fees, nil
// calculate priority based on effective gas price
tipPrice := txData.EffectiveGasPrice(baseFee)
// if london hardfork is not enabled, tipPrice is the gasPrice
if baseFee != nil {
tipPrice = new(big.Int).Sub(tipPrice, baseFee)
}
priorityBig := new(big.Int).Quo(tipPrice, evmtypes.DefaultPriorityReduction.BigInt())
if !priorityBig.IsInt64() {
priority = math.MaxInt64
} else {
priority = priorityBig.Int64()
}
return fees, priority, nil
}
// CheckSenderBalance validates that the tx cost value is positive and that the
// sender has enough funds to pay for the fees and value of the transaction.
func CheckSenderBalance(
balance sdk.Int,
balance sdkmath.Int,
txData evmtypes.TxData,
) error {
cost := txData.Cost()
+19 -17
View File
@@ -3,6 +3,7 @@ package keeper_test
import (
"math/big"
sdkmath "cosmossdk.io/math"
evmkeeper "github.com/cerc-io/laconicd/x/evm/keeper"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -12,21 +13,21 @@ import (
)
func (suite *KeeperTestSuite) TestCheckSenderBalance() {
hundredInt := sdk.NewInt(100)
hundredInt := sdkmath.NewInt(100)
zeroInt := sdk.ZeroInt()
oneInt := sdk.OneInt()
fiveInt := sdk.NewInt(5)
fiftyInt := sdk.NewInt(50)
negInt := sdk.NewInt(-10)
fiveInt := sdkmath.NewInt(5)
fiftyInt := sdkmath.NewInt(50)
negInt := sdkmath.NewInt(-10)
testCases := []struct {
name string
to string
gasLimit uint64
gasPrice *sdk.Int
gasPrice *sdkmath.Int
gasFeeCap *big.Int
gasTipCap *big.Int
cost *sdk.Int
cost *sdkmath.Int
from string
accessList *ethtypes.AccessList
expectPass bool
@@ -237,7 +238,7 @@ func (suite *KeeperTestSuite) TestCheckSenderBalance() {
acct := suite.app.EvmKeeper.GetAccountOrEmpty(suite.ctx, suite.address)
err := evmkeeper.CheckSenderBalance(
sdk.NewIntFromBigInt(acct.Balance),
sdkmath.NewIntFromBigInt(acct.Balance),
txData,
)
@@ -251,22 +252,22 @@ func (suite *KeeperTestSuite) TestCheckSenderBalance() {
}
func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
hundredInt := sdk.NewInt(100)
hundredInt := sdkmath.NewInt(100)
zeroInt := sdk.ZeroInt()
oneInt := sdk.NewInt(1)
fiveInt := sdk.NewInt(5)
fiftyInt := sdk.NewInt(50)
oneInt := sdkmath.NewInt(1)
fiveInt := sdkmath.NewInt(5)
fiftyInt := sdkmath.NewInt(50)
// should be enough to cover all test cases
initBalance := sdk.NewInt((ethparams.InitialBaseFee + 10) * 105)
initBalance := sdkmath.NewInt((ethparams.InitialBaseFee + 10) * 105)
testCases := []struct {
name string
gasLimit uint64
gasPrice *sdk.Int
gasPrice *sdkmath.Int
gasFeeCap *big.Int
gasTipCap *big.Int
cost *sdk.Int
cost *sdkmath.Int
accessList *ethtypes.AccessList
expectPass bool
enableFeemarket bool
@@ -402,7 +403,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
txData, _ := evmtypes.UnpackTxData(tx.Data)
fees, err := suite.app.EvmKeeper.DeductTxCostsFromUserBalance(
fees, priority, err := suite.app.EvmKeeper.DeductTxCostsFromUserBalance(
suite.ctx,
*tx,
txData,
@@ -419,15 +420,16 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
suite.Require().Equal(
fees,
sdk.NewCoins(
sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewIntFromBigInt(txData.EffectiveFee(baseFee))),
sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewIntFromBigInt(txData.EffectiveFee(baseFee))),
),
"valid test %d failed, fee value is wrong ", i,
)
suite.Require().Equal(int64(0), priority)
} else {
suite.Require().Equal(
fees,
sdk.NewCoins(
sdk.NewCoin(evmtypes.DefaultEVMDenom, tc.gasPrice.Mul(sdk.NewIntFromUint64(tc.gasLimit))),
sdk.NewCoin(evmtypes.DefaultEVMDenom, tc.gasPrice.Mul(sdkmath.NewIntFromUint64(tc.gasLimit))),
),
"valid test %d failed, fee value is wrong ", i,
)