Skip to content

Commit

Permalink
Merge branch 'develop' into bump_cometbft
Browse files Browse the repository at this point in the history
  • Loading branch information
yihuang authored Nov 14, 2024
2 parents 0faa6c8 + 6464c22 commit eb60490
Show file tree
Hide file tree
Showing 16 changed files with 297 additions and 142 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (cli) [#537](https://github.com/crypto-org-chain/ethermint/pull/537) Fix unsuppored sign mode SIGN_MODE_TEXTUAL for bank transfer.
* (cli) [#543](https://github.com/crypto-org-chain/ethermint/pull/543) Fix graceful shutdown.
* (rpc) [#545](https://github.com/crypto-org-chain/ethermint/pull/545) Fix state overwrite in debug trace APIs.
* (rpc) [#554](https://github.com/crypto-org-chain/ethermint/pull/554) No trace detail on insufficient balance.
* (rpc) [#558](https://github.com/crypto-org-chain/ethermint/pull/558) New tracer in predecessors to trace balance correctly when `debug_traceTransaction`.
* (rpc) [#559](https://github.com/crypto-org-chain/ethermint/pull/559) Use basefee of transaction height instead of minus one height when `debug_traceTransaction`.
* (ante) [#560](https://github.com/crypto-org-chain/ethermint/pull/560) Check gasWanted only in checkTx mode.
* (rpc) [#562](https://github.com/crypto-org-chain/ethermint/pull/562) Fix nil pointer panic with legacy transaction format.

### Improvements

Expand Down
2 changes: 1 addition & 1 deletion app/ante/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func CheckEthGasConsume(

// We can't trust the tx gas limit, because we'll refund the unused gas.
gasLimit := msgEthTx.GetGas()
if maxGasWanted != 0 {
if ctx.IsCheckTx() && maxGasWanted != 0 {
gasLimit = min(gasLimit, maxGasWanted)
}
if gasWanted > math.MaxInt64-gasLimit {
Expand Down
9 changes: 8 additions & 1 deletion client/docs/swagger-ui/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3730,12 +3730,19 @@ paths:
format: byte
- name: chain_id
description: >-
chain_id is the the eip155 chain id parsed from the requested block
chain_id is the eip155 chain id parsed from the requested block
header.
in: query
required: false
type: string
format: int64
- name: base_fee
description: >-
base_fee is the base fee based on the block_number of requested
transaction.
in: query
required: false
type: string
tags:
- Query
/ethermint/evm/v1/validator_account/{cons_address}:
Expand Down
4 changes: 3 additions & 1 deletion proto/ethermint/evm/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,10 @@ message QueryTraceTxRequest {
google.protobuf.Timestamp block_time = 7 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
// proposer_address is the proposer of the requested block
bytes proposer_address = 8 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ConsAddress"];
// chain_id is the the eip155 chain id parsed from the requested block header
// chain_id is the eip155 chain id parsed from the requested block header
int64 chain_id = 9;
// base_fee is the base fee based on the block_number of requested transaction
string base_fee = 10 [(gogoproto.customtype) = "cosmossdk.io/math.Int"];
}

// QueryTraceTxResponse defines TraceTx response
Expand Down
7 changes: 7 additions & 0 deletions rpc/backend/tracing.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
rpctypes "github.com/evmos/ethermint/rpc/types"
ethermint "github.com/evmos/ethermint/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -117,6 +118,12 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *rpctypes.TraceConfi
// 0 is a special value in `ContextWithHeight`
contextHeight = 1
}
// Get basefee from transaction height
res, err := b.queryClient.FeeMarket.Params(rpctypes.ContextWithHeight(transaction.Height), &feemarkettypes.QueryParamsRequest{})
if err != nil {
return nil, err
}
traceTxRequest.BaseFee = &res.Params.BaseFee
traceResult, err := b.queryClient.TraceTx(rpctypes.ContextWithHeight(contextHeight), &traceTxRequest)
if err != nil {
return nil, err
Expand Down
4 changes: 4 additions & 0 deletions rpc/backend/tracing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ func (suite *BackendTestSuite) TestTraceTransaction() {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockMultipleTxs(client, 1, []types.Tx{txBz, txBz2})
feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient)
RegisterFeeMarketParams(feeMarketClient, 1)
RegisterTraceTransactionWithPredecessors(queryClient, msgEthereumTx, []*evmtypes.MsgEthereumTx{msgEthereumTx})
},
&types.Block{Header: types.Header{Height: 1, ChainID: ChainID}, Data: types.Data{Txs: []types.Tx{txBz, txBz2}}},
Expand Down Expand Up @@ -169,6 +171,8 @@ func (suite *BackendTestSuite) TestTraceTransaction() {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlock(client, 1, txBz)
feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient)
RegisterFeeMarketParams(feeMarketClient, 1)
RegisterTraceTransaction(queryClient, msgEthereumTx)
},
&types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz}}},
Expand Down
8 changes: 4 additions & 4 deletions rpc/types/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,9 @@ func BaseFeeFromEvents(events []abci.Event) *big.Int {

// CheckTxFee is an internal function used to check whether the fee of
// the given transaction is _reasonable_(under the cap).
func CheckTxFee(gasPrice *big.Int, gas uint64, cap float64) error {
func CheckTxFee(gasPrice *big.Int, gas uint64, feeCap float64) error {
// Short circuit if there is no cap for transaction fee at all.
if cap == 0 {
if feeCap == 0 {
return nil
}
totalfee := new(big.Float).SetInt(new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(gas)))
Expand All @@ -300,8 +300,8 @@ func CheckTxFee(gasPrice *big.Int, gas uint64, cap float64) error {
feeEth := new(big.Float).Quo(totalfee, oneToken)
// no need to check error from parsing
feeFloat, _ := feeEth.Float64()
if feeFloat > cap {
return fmt.Errorf("tx fee (%.2f ether) exceeds the configured cap (%.2f ether)", feeFloat, cap)
if feeFloat > feeCap {
return fmt.Errorf("tx fee (%.2f ether) exceeds the configured cap (%.2f ether)", feeFloat, feeCap)
}
return nil
}
Expand Down
10 changes: 10 additions & 0 deletions tests/integration_tests/hardhat/contracts/FeeCollector.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract FeeCollector {
event TokensMinted(address indexed to, uint256 amount);

function mint(uint256 amount) public payable {
emit TokensMinted(msg.sender, amount);
}
}
37 changes: 36 additions & 1 deletion tests/integration_tests/test_tracers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
deploy_contract,
derive_new_account,
derive_random_account,
send_raw_transactions,
send_transaction,
send_txs,
sign_transaction,
w3_wait_for_new_blocks,
)

Expand Down Expand Up @@ -156,6 +158,39 @@ def process(w3):
assert res[0] == res[-1], res


def test_trace_tx_reverse_transfer(ethermint):
print("reproduce only")
return
method = "debug_traceTransaction"
tracer = {"tracer": "callTracer"}
acc = derive_new_account(11)
w3 = ethermint.w3
fund_acc(w3, acc, fund=40000000000000000)
contract, _ = deploy_contract(w3, CONTRACTS["FeeCollector"])
amt = 18633908679862681
raw_transactions = []
nonce = w3.eth.get_transaction_count(acc.address)
tx = contract.functions.mint(amt).build_transaction(
{
"from": acc.address,
"value": hex(amt),
"nonce": nonce,
}
)
raw_transactions.append(sign_transaction(w3, tx, acc.key).rawTransaction)
tx = tx | {"nonce": nonce + 1}
raw_transactions.append(sign_transaction(w3, tx, acc.key).rawTransaction)
w3_wait_for_new_blocks(w3, 1)
sended_hash_set = send_raw_transactions(w3, raw_transactions)
for h in sended_hash_set:
tx_hash = h.hex()
tx_res = w3.provider.make_request(
method,
[tx_hash, tracer],
)
print(tx_res)


def test_tracecall_insufficient_funds(ethermint, geth):
method = "debug_traceCall"
acc = derive_random_account()
Expand Down Expand Up @@ -540,7 +575,7 @@ def test_refund_unused_gas_when_contract_tx_reverted_state_overrides(ethermint):
"balance": hex(balance),
"nonce": hex(nonce),
}
}
},
},
],
)
Expand Down
1 change: 1 addition & 0 deletions tests/integration_tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"Caller": "Caller.sol",
"Random": "Random.sol",
"TestBlockTxProperties": "TestBlockTxProperties.sol",
"FeeCollector": "FeeCollector.sol",
}


Expand Down
4 changes: 2 additions & 2 deletions types/dynamic_fee.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
)

// HasDynamicFeeExtensionOption returns true if the tx implements the `ExtensionOptionDynamicFeeTx` extension option.
func HasDynamicFeeExtensionOption(any *codectypes.Any) bool {
_, ok := any.GetCachedValue().(*ExtensionOptionDynamicFeeTx)
func HasDynamicFeeExtensionOption(codecAny *codectypes.Any) bool {
_, ok := codecAny.GetCachedValue().(*ExtensionOptionDynamicFeeTx)
return ok
}
76 changes: 48 additions & 28 deletions x/evm/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (

rpctypes "github.com/evmos/ethermint/rpc/types"
ethermint "github.com/evmos/ethermint/types"
"github.com/evmos/ethermint/x/evm/statedb"
"github.com/evmos/ethermint/x/evm/types"
)

Expand Down Expand Up @@ -421,9 +422,11 @@ func execTrace[T traceRequest](
c context.Context,
req T,
k Keeper,
baseFee *big.Int,
msgCb func(
ctx sdk.Context,
cfg *EVMConfig,
traceConfig *types.TraceConfig,
) (*core.Message, error),
) ([]byte, error) {
var zero T
Expand Down Expand Up @@ -457,7 +460,11 @@ func execTrace[T traceRequest](
return nil, status.Errorf(codes.Internal, "failed to load evm config: %s", err.Error())
}

msg, err := msgCb(ctx, cfg)
if baseFee != nil {
cfg.BaseFee = baseFee
}

msg, err := msgCb(ctx, cfg, req.GetTraceConfig())
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
Expand All @@ -480,13 +487,23 @@ func execTrace[T traceRequest](
// executes the given message in the provided environment. The return value will
// be tracer dependent.
func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*types.QueryTraceTxResponse, error) {
var baseFee *big.Int
if req != nil && req.BaseFee != nil {
baseFee = big.NewInt(req.BaseFee.Int64())
}
resultData, err := execTrace(
c,
req,
k,
func(ctx sdk.Context, cfg *EVMConfig) (*core.Message, error) {
baseFee,
func(ctx sdk.Context, cfg *EVMConfig, traceConfig *types.TraceConfig) (*core.Message, error) {
signer := ethtypes.MakeSigner(cfg.ChainConfig, big.NewInt(ctx.BlockHeight()))
cfg.Tracer = types.NewNoOpTracer()
tracer, err := newTacer(&logger.Config{}, cfg.TxConfig, traceConfig)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
cfg.Tracer = tracer
cfg.DebugTrace = true
for i, tx := range req.Predecessors {
ethTx := tx.AsTransaction()
msg, err := core.TransactionToMessage(ethTx, signer, cfg.BaseFee)
Expand Down Expand Up @@ -601,7 +618,8 @@ func (k Keeper) TraceCall(c context.Context, req *types.QueryTraceCallRequest) (
c,
req,
k,
func(ctx sdk.Context, cfg *EVMConfig) (*core.Message, error) {
nil,
func(ctx sdk.Context, cfg *EVMConfig, _ *types.TraceConfig) (*core.Message, error) {
var args types.TransactionArgs
err := json.Unmarshal(req.Args, &args)
if err != nil {
Expand All @@ -628,6 +646,31 @@ func (k Keeper) TraceCall(c context.Context, req *types.QueryTraceCallRequest) (
}, nil
}

func newTacer(logConfig *logger.Config, txConfig statedb.TxConfig, traceConfig *types.TraceConfig) (tracers.Tracer, error) {
tracer := logger.NewStructLogger(logConfig)
if traceConfig != nil && traceConfig.Tracer != "" {
txIndex, err := ethermint.SafeInt(txConfig.TxIndex)
if err != nil {
return nil, err
}
tCtx := &tracers.Context{
BlockHash: txConfig.BlockHash,
TxIndex: txIndex,
TxHash: txConfig.TxHash,
}
var cfg json.RawMessage
if traceConfig.TracerJsonConfig != "" {
cfg = json.RawMessage(traceConfig.TracerJsonConfig)
}
tracer, err := tracers.DefaultDirectory.New(traceConfig.Tracer, tCtx, cfg)
if err != nil {
return nil, err
}
return tracer, nil
}
return tracer, nil
}

// prepareTrace prepare trace on one Ethereum message, it returns a tuple: (traceResult, nextLogIndex, error).
func (k *Keeper) prepareTrace(
ctx sdk.Context,
Expand Down Expand Up @@ -663,28 +706,11 @@ func (k *Keeper) prepareTrace(
Overrides: overrides,
}

tracer = logger.NewStructLogger(&logConfig)

txIndex, err := ethermint.SafeInt(txConfig.TxIndex)
tracer, err = newTacer(&logConfig, txConfig, traceConfig)
if err != nil {
return nil, 0, status.Error(codes.Internal, err.Error())
}

tCtx := &tracers.Context{
BlockHash: txConfig.BlockHash,
TxIndex: txIndex,
TxHash: txConfig.TxHash,
}
if traceConfig.Tracer != "" {
var cfg json.RawMessage
if traceConfig.TracerJsonConfig != "" {
cfg = json.RawMessage(traceConfig.TracerJsonConfig)
}
if tracer, err = tracers.DefaultDirectory.New(traceConfig.Tracer, tCtx, cfg); err != nil {
return nil, 0, status.Error(codes.Internal, err.Error())
}
}

// Define a meaningful timeout of a single transaction trace
if traceConfig.Timeout != "" {
if timeout, err = time.ParseDuration(traceConfig.Timeout); err != nil {
Expand Down Expand Up @@ -728,12 +754,6 @@ func (k *Keeper) prepareTrace(
return nil, 0, status.Error(codes.Internal, err.Error())
}

if res.VmError != "" {
if res.VmError == vm.ErrInsufficientBalance.Error() {
return nil, 0, status.Error(codes.Internal, res.VmError)
}
}

var result interface{}
result, err = tracer.GetResult()
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions x/evm/types/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,14 @@ func PackTxData(txData TxData) (*codectypes.Any, error) {

// UnpackTxData unpacks an Any into a TxData. It returns an error if the
// client state can't be unpacked into a TxData.
func UnpackTxData(any *codectypes.Any) (TxData, error) {
if any == nil {
func UnpackTxData(codecAny *codectypes.Any) (TxData, error) {
if codecAny == nil {
return nil, errorsmod.Wrap(errortypes.ErrUnpackAny, "protobuf Any message cannot be nil")
}

txData, ok := any.GetCachedValue().(TxData)
txData, ok := codecAny.GetCachedValue().(TxData)
if !ok {
return nil, errorsmod.Wrapf(errortypes.ErrUnpackAny, "cannot unpack Any into TxData %T", any)
return nil, errorsmod.Wrapf(errortypes.ErrUnpackAny, "cannot unpack Any into TxData %T", codecAny)
}

return txData, nil
Expand Down
8 changes: 8 additions & 0 deletions x/evm/types/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"

errorsmod "cosmossdk.io/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/evmos/ethermint/types"
Expand Down Expand Up @@ -60,6 +61,9 @@ func (tx *EthereumTx) UnmarshalJSON(bz []byte) error {
}

func (tx EthereumTx) MarshalJSON() ([]byte, error) {
if tx.Transaction == nil {
return []byte("null"), nil
}
bz, err := tx.MarshalBinary()
if err != nil {
return nil, err
Expand All @@ -68,6 +72,10 @@ func (tx EthereumTx) MarshalJSON() ([]byte, error) {
}

func (tx EthereumTx) Validate() error {
if tx.Transaction == nil {
return errorsmod.Wrapf(errortypes.ErrInvalidRequest, "raw tx is missing")
}

// prevent txs with 0 gas to fill up the mempool
if tx.Gas() == 0 {
return errorsmod.Wrap(ErrInvalidGasLimit, "gas limit must not be zero")
Expand Down
Loading

0 comments on commit eb60490

Please sign in to comment.