diff --git a/indexer/kv_indexer.go b/indexer/kv_indexer.go index c6ca943a67..a4bd61d308 100644 --- a/indexer/kv_indexer.go +++ b/indexer/kv_indexer.go @@ -190,8 +190,16 @@ func TxHashKey(hash common.Hash) []byte { // TxIndexKey returns the key for db entry: `(block number, tx index) -> tx hash` func TxIndexKey(blockNumber int64, txIndex int32) []byte { - bz1 := sdk.Uint64ToBigEndian(uint64(blockNumber)) - bz2 := sdk.Uint64ToBigEndian(uint64(txIndex)) + value, err := ethermint.SafeUint64(blockNumber) + if err != nil { + panic(err) + } + bz1 := sdk.Uint64ToBigEndian(value) + value, err = ethermint.SafeInt32ToUint64(txIndex) + if err != nil { + panic(err) + } + bz2 := sdk.Uint64ToBigEndian(value) return append(append([]byte{KeyPrefixTxIndex}, bz1...), bz2...) } diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index 4b7f70a1d2..26aff3f7d8 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -385,7 +385,10 @@ func (b *Backend) RPCBlockFromTendermintBlock( ) (map[string]interface{}, error) { ethRPCTxs := []interface{}{} block := resBlock.Block - + height, err := ethermint.SafeUint64(block.Height) + if err != nil { + return nil, err + } baseFee, err := b.BaseFee(blockRes) if err != nil { // handle the error for pruned node. @@ -398,12 +401,15 @@ func (b *Backend) RPCBlockFromTendermintBlock( ethRPCTxs = append(ethRPCTxs, ethMsg.Hash()) continue } - + index, err := ethermint.SafeIntToUint64(txIndex) + if err != nil { + return nil, err + } rpcTx, err := rpctypes.NewRPCTransaction( ethMsg, common.BytesToHash(block.Hash()), - uint64(block.Height), - uint64(txIndex), + height, + index, baseFee, b.chainID, ) @@ -450,15 +456,18 @@ func (b *Backend) RPCBlockFromTendermintBlock( b.logger.Error("failed to query consensus params", "error", err.Error()) } - gasUsed := uint64(0) - + var gasUsed uint64 for _, txsResult := range blockRes.TxsResults { // workaround for cosmos-sdk bug. https://github.com/cosmos/cosmos-sdk/issues/10832 if ShouldIgnoreGasUsed(txsResult) { // block gas limit has exceeded, other txs must have failed with same reason. break } - gasUsed += uint64(txsResult.GetGasUsed()) + gas, err := ethermint.SafeUint64(txsResult.GetGasUsed()) + if err != nil { + return nil, err + } + gasUsed += gas } formattedBlock := rpctypes.FormatBlock( diff --git a/rpc/backend/chain_info.go b/rpc/backend/chain_info.go index f2af291057..4f9d4c4d67 100644 --- a/rpc/backend/chain_info.go +++ b/rpc/backend/chain_info.go @@ -295,7 +295,7 @@ func (b *Backend) FeeHistory( } } } - }(int32(value)) //nolint:gosec // checked + }(int32(value)) } go func() { wg.Wait() diff --git a/rpc/backend/node_info.go b/rpc/backend/node_info.go index 94745a040b..764ec1c1fc 100644 --- a/rpc/backend/node_info.go +++ b/rpc/backend/node_info.go @@ -78,10 +78,17 @@ func (b *Backend) Syncing() (interface{}, error) { if !status.SyncInfo.CatchingUp { return false, nil } - + start, err := ethermint.SafeUint64(status.SyncInfo.EarliestBlockHeight) + if err != nil { + return false, err + } + current, err := ethermint.SafeUint64(status.SyncInfo.LatestBlockHeight) + if err != nil { + return false, err + } return map[string]interface{}{ - "startingBlock": hexutil.Uint64(status.SyncInfo.EarliestBlockHeight), - "currentBlock": hexutil.Uint64(status.SyncInfo.LatestBlockHeight), + "startingBlock": hexutil.Uint64(start), + "currentBlock": hexutil.Uint64(current), // "highestBlock": nil, // NA // "pulledStates": nil, // NA // "knownStates": nil, // NA diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index e004b413ee..c1ad777ad0 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -38,7 +38,14 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac if err != nil { return b.getTransactionByHashPending(txHash) } - + height, err := ethermint.SafeUint64(res.Height) + if err != nil { + return nil, err + } + index, err := ethermint.SafeInt32ToUint64(res.EthTxIndex) + if err != nil { + return nil, err + } block, err := b.TendermintBlockByNumber(rpctypes.BlockNumber(res.Height)) if err != nil { return nil, err @@ -85,12 +92,11 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac // handle the error for pruned node. b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", blockRes.Height, "error", err) } - return rpctypes.NewTransactionFromMsg( msg, common.BytesToHash(block.BlockID.Hash.Bytes()), - uint64(res.Height), - uint64(res.EthTxIndex), + height, + index, baseFee, b.chainID, ) @@ -171,14 +177,18 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ return nil, err } - cumulativeGasUsed := uint64(0) + var cumulativeGasUsed uint64 blockRes, err := b.TendermintBlockResultByNumber(&res.Height) if err != nil { b.logger.Debug("failed to retrieve block results", "height", res.Height, "error", err.Error()) return nil, nil } for _, txResult := range blockRes.TxsResults[0:res.TxIndex] { - cumulativeGasUsed += uint64(txResult.GasUsed) + gas, err := ethermint.SafeUint64(txResult.GasUsed) + if err != nil { + return nil, err + } + cumulativeGasUsed += gas } cumulativeGasUsed += res.CumulativeGasUsed @@ -198,12 +208,16 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ return nil, err } + height, err := ethermint.SafeUint64(blockRes.Height) + if err != nil { + return nil, err + } // parse tx logs from events logs, err := evmtypes.DecodeMsgLogsFromEvents( blockRes.TxsResults[res.TxIndex].Data, blockRes.TxsResults[res.TxIndex].Events, int(res.MsgIndex), - uint64(blockRes.Height), + height, ) if err != nil { b.logger.Debug("failed to parse logs", "hash", hash, "error", err.Error()) @@ -228,6 +242,14 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ return nil, errors.New("can't find index of ethereum tx") } + blockNumber, err := ethermint.SafeUint64(res.Height) + if err != nil { + return nil, err + } + transactionIndex, err := ethermint.SafeInt32ToUint64(res.EthTxIndex) + if err != nil { + return nil, err + } receipt := map[string]interface{}{ // Consensus fields: These fields are defined by the Yellow Paper "status": status, @@ -244,8 +266,8 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ // Inclusion information: These fields provide information about the inclusion of the // transaction corresponding to this receipt. "blockHash": common.BytesToHash(resBlock.Block.Header.Hash()).Hex(), - "blockNumber": hexutil.Uint64(res.Height), - "transactionIndex": hexutil.Uint64(res.EthTxIndex), + "blockNumber": hexutil.Uint64(blockNumber), + "transactionIndex": hexutil.Uint64(transactionIndex), // sender and receiver (contract or EOA) addreses "from": from, @@ -433,10 +455,15 @@ func (b *Backend) GetTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, i b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", block.Block.Height, "error", err) } + height, err := ethermint.SafeUint64(block.Block.Height) + if err != nil { + return nil, err + } + return rpctypes.NewTransactionFromMsg( msg, common.BytesToHash(block.Block.Hash()), - uint64(block.Block.Height), + height, uint64(idx), baseFee, b.chainID, diff --git a/rpc/backend/utils.go b/rpc/backend/utils.go index 46760319f0..f236b994da 100644 --- a/rpc/backend/utils.go +++ b/rpc/backend/utils.go @@ -39,6 +39,7 @@ import ( "github.com/cometbft/cometbft/proto/tendermint/crypto" "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" ) @@ -244,7 +245,10 @@ func (b *Backend) processBlock( b.logger.Debug("failed to decode transaction in block", "height", blockHeight, "error", err.Error()) continue } - txGasUsed := uint64(eachTendermintTxResult.GasUsed) + txGasUsed, err := ethermint.SafeUint64(eachTendermintTxResult.GasUsed) + if err != nil { + return err + } for _, msg := range tx.GetMsgs() { ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { @@ -290,9 +294,13 @@ func ShouldIgnoreGasUsed(res *abci.ExecTxResult) bool { // GetLogsFromBlockResults returns the list of event logs from the tendermint block result response func GetLogsFromBlockResults(blockRes *tmrpctypes.ResultBlockResults) ([][]*ethtypes.Log, error) { + height, err := ethermint.SafeUint64(blockRes.Height) + if err != nil { + return nil, err + } blockLogs := [][]*ethtypes.Log{} for _, txResult := range blockRes.TxsResults { - logs, err := evmtypes.DecodeTxLogsFromEvents(txResult.Data, txResult.Events, uint64(blockRes.Height)) + logs, err := evmtypes.DecodeTxLogsFromEvents(txResult.Data, txResult.Events, height) if err != nil { return nil, err } diff --git a/rpc/namespaces/ethereum/debug/api.go b/rpc/namespaces/ethereum/debug/api.go index 52219c9685..7860f915ee 100644 --- a/rpc/namespaces/ethereum/debug/api.go +++ b/rpc/namespaces/ethereum/debug/api.go @@ -132,7 +132,7 @@ func parseDuration(nsec uint) (time.Duration, error) { if nsec > uint(time.Duration(1<<63-1)/time.Second) { return time.Duration(0), fmt.Errorf("value %d exceeds maximum duration for time.Duration", nsec) } - return time.Duration(nsec) * time.Second, nil //nolint:gosec // checked + return time.Duration(nsec) * time.Second, nil } // BlockProfile turns on goroutine profiling for nsec seconds and writes profile data to diff --git a/rpc/namespaces/ethereum/eth/api.go b/rpc/namespaces/ethereum/eth/api.go index df9c8577a3..2572f1726e 100644 --- a/rpc/namespaces/ethereum/eth/api.go +++ b/rpc/namespaces/ethereum/eth/api.go @@ -448,13 +448,16 @@ func (e *PublicAPI) GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, err e.logger.Debug("block result not found", "number", res.Height, "error", err.Error()) return nil, nil } - + height, err := ethermint.SafeUint64(resBlockResult.Height) + if err != nil { + return nil, err + } // parse tx logs from events logs, err := evmtypes.DecodeMsgLogsFromEvents( resBlockResult.TxsResults[res.TxIndex].Data, resBlockResult.TxsResults[res.TxIndex].Events, int(res.MsgIndex), - uint64(resBlockResult.Height), + height, ) if err != nil { e.logger.Debug("failed to parse tx logs", "error", err.Error()) diff --git a/rpc/stream/rpc.go b/rpc/stream/rpc.go index d23388ada7..680cfc67e7 100644 --- a/rpc/stream/rpc.go +++ b/rpc/stream/rpc.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/evmos/ethermint/rpc/types" + ethermint "github.com/evmos/ethermint/types" evmtypes "github.com/evmos/ethermint/x/evm/types" ) @@ -167,7 +168,11 @@ func (s *RPCStream) start( s.logger.Error("event data type mismatch", "type", fmt.Sprintf("%T", ev.Data)) continue } - txLogs, err := evmtypes.DecodeTxLogsFromEvents(dataTx.TxResult.Result.Data, dataTx.TxResult.Result.Events, uint64(dataTx.TxResult.Height)) + height, err := ethermint.SafeUint64(dataTx.TxResult.Height) + if err != nil { + continue + } + txLogs, err := evmtypes.DecodeTxLogsFromEvents(dataTx.TxResult.Result.Data, dataTx.TxResult.Result.Events, height) if err != nil { s.logger.Error("fail to decode evm tx response", "error", err.Error()) continue diff --git a/rpc/types/events.go b/rpc/types/events.go index 16bc3f46ef..0b53f5e282 100644 --- a/rpc/types/events.go +++ b/rpc/types/events.go @@ -135,7 +135,11 @@ func ParseTxResult(result *abci.ExecTxResult, tx sdk.Tx) (*ParsedTxs, error) { // some old versions miss some events, fill it with tx result if len(p.Txs) == 1 { - p.Txs[0].GasUsed = uint64(result.GasUsed) + value, err := ethermint.SafeUint64(result.GasUsed) + if err != nil { + return nil, err + } + p.Txs[0].GasUsed = value } // this could only happen if tx exceeds block gas limit diff --git a/rpc/types/utils.go b/rpc/types/utils.go index fb7b0facfc..84f6f4faba 100644 --- a/rpc/types/utils.go +++ b/rpc/types/utils.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" + ethermint "github.com/evmos/ethermint/types" ) // ExceedBlockGasLimitError defines the error message when tx execution exceeds the block gas limit. @@ -69,6 +70,10 @@ func EthHeaderFromTendermint(header tmtypes.Header, bloom ethtypes.Bloom, baseFe txHash = common.BytesToHash(header.DataHash) } + value, err := ethermint.SafeUint64(header.Time.UTC().Unix()) + if err != nil { + panic(err) + } return ðtypes.Header{ ParentHash: common.BytesToHash(header.LastBlockID.Hash.Bytes()), UncleHash: ethtypes.EmptyUncleHash, @@ -81,7 +86,7 @@ func EthHeaderFromTendermint(header tmtypes.Header, bloom ethtypes.Bloom, baseFe Number: big.NewInt(header.Height), GasLimit: 0, GasUsed: 0, - Time: uint64(header.Time.UTC().Unix()), + Time: value, Extra: []byte{}, MixDigest: common.Hash{}, Nonce: ethtypes.BlockNonce{}, @@ -125,9 +130,24 @@ func FormatBlock( } else { transactionsRoot = common.BytesToHash(header.DataHash) } - + number, err := ethermint.SafeUint64(header.Height) + if err != nil { + panic(err) + } + limit, err := ethermint.SafeUint64(gasLimit) + if err != nil { + panic(err) + } + timestamp, err := ethermint.SafeUint64(header.Time.Unix()) + if err != nil { + panic(err) + } + s, err := ethermint.SafeIntToUint64(size) + if err != nil { + panic(err) + } result := map[string]interface{}{ - "number": hexutil.Uint64(header.Height), + "number": hexutil.Uint64(number), "hash": hexutil.Bytes(header.Hash()), "parentHash": common.BytesToHash(header.LastBlockID.Hash.Bytes()), "nonce": ethtypes.BlockNonce{}, // PoW specific @@ -138,10 +158,10 @@ func FormatBlock( "mixHash": common.Hash{}, "difficulty": (*hexutil.Big)(big.NewInt(0)), "extraData": "0x", - "size": hexutil.Uint64(size), - "gasLimit": hexutil.Uint64(gasLimit), // Static gas limit + "size": hexutil.Uint64(s), + "gasLimit": limit, // Static gas limit "gasUsed": (*hexutil.Big)(gasUsed), - "timestamp": hexutil.Uint64(header.Time.Unix()), + "timestamp": hexutil.Uint64(timestamp), "transactionsRoot": transactionsRoot, "receiptsRoot": ethtypes.EmptyRootHash, diff --git a/testutil/base_test_suite.go b/testutil/base_test_suite.go index 4136d45268..ab74ece864 100644 --- a/testutil/base_test_suite.go +++ b/testutil/base_test_suite.go @@ -61,7 +61,7 @@ func (suite *BaseTestSuite) MintFeeCollectorVirtual(coins sdk.Coins) { func addVirtualCoins(store storetypes.ObjKVStore, txIndex int, addr sdk.AccAddress, amt sdk.Coins) { key := make([]byte, len(addr)+8) copy(key, addr) - binary.BigEndian.PutUint64(key[len(addr):], uint64(txIndex)) + binary.BigEndian.PutUint64(key[len(addr):], uint64(txIndex)) //nolint:gosec // test only var coins sdk.Coins value := store.Get(key) diff --git a/types/int.go b/types/int.go index 3c717d3c68..de02539067 100644 --- a/types/int.go +++ b/types/int.go @@ -42,7 +42,7 @@ func SafeInt64(value uint64) (int64, error) { return 0, fmt.Errorf("uint64 value %v cannot exceed %v", value, math.MaxInt64) } - return int64(value), nil //nolint:gosec // checked + return int64(value), nil } func SafeUint64ToInt32(value uint64) (int32, error) { @@ -58,7 +58,7 @@ func SafeUint64ToInt(value uint64) (int, error) { return 0, fmt.Errorf("uint64 value %v cannot exceed %v", value, math.MaxInt64) } - return int(value), nil //nolint:gosec // checked + return int(value), nil } func SafeHexToInt64(value hexutil.Uint64) (int64, error) { @@ -77,12 +77,40 @@ func SafeUint32(value int) (uint32, error) { return uint32(value), nil //nolint:gosec // checked } +func SafeUint64(value int64) (uint64, error) { + if value < 0 { + return 0, fmt.Errorf("invalid value: %d", value) + } + return uint64(value), nil +} + +func SafeIntToUint64(value int) (uint64, error) { + if value < 0 { + return 0, fmt.Errorf("invalid value: %d", value) + } + return uint64(value), nil +} + +func SafeInt32ToUint64(value int32) (uint64, error) { + if value < 0 { + return 0, fmt.Errorf("invalid value: %d", value) + } + return uint64(value), nil +} + +func SafeUint(value int) (uint, error) { + if value < 0 { + return 0, fmt.Errorf("invalid value: %d", value) + } + return uint(value), nil +} + func SafeUintToInt32(value uint) (int32, error) { if value > uint(math.MaxInt32) { return 0, fmt.Errorf("uint value %v cannot exceed %v", value, math.MaxUint32) } - return int32(value), nil //nolint:gosec // checked + return int32(value), nil } func SafeIntToInt32(value int) (int32, error) { @@ -98,7 +126,7 @@ func SafeInt(value uint) (int, error) { return 0, fmt.Errorf("uint value %v cannot exceed %v", value, math.MaxInt64) } - return int(value), nil //nolint:gosec // checked + return int(value), nil } func SafeHexToInt(value hexutil.Uint) (int, error) { diff --git a/x/evm/keeper/config.go b/x/evm/keeper/config.go index 4a19709975..6b7941425f 100644 --- a/x/evm/keeper/config.go +++ b/x/evm/keeper/config.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" 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" feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" @@ -85,8 +86,10 @@ func (k *Keeper) EVMBlockConfig(ctx sdk.Context, chainID *big.Int) (*EVMBlockCon baseFee = new(big.Int) } } - - blockTime := uint64(ctx.BlockHeader().Time.Unix()) + blockTime, err := ethermint.SafeUint64(ctx.BlockHeader().Time.Unix()) + if err != nil { + return nil, err + } blockNumber := big.NewInt(ctx.BlockHeight()) rules := ethCfg.Rules(blockNumber, ethCfg.MergeNetsplitBlock != nil, blockTime) diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index 30bed2e3b8..12179d35f4 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -315,7 +315,10 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type // Query block gas limit params := ctx.ConsensusParams() if params.Block != nil && params.Block.MaxGas > 0 { - hi = uint64(params.Block.MaxGas) + hi, err = ethermint.SafeUint64(params.Block.MaxGas) + if err != nil { + return nil, err + } } else { hi = req.GasCap } @@ -491,7 +494,10 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ continue } cfg.TxConfig.TxHash = ethTx.Hash() - cfg.TxConfig.TxIndex = uint(i) + cfg.TxConfig.TxIndex, err = ethermint.SafeUint(i) + if err != nil { + continue + } rsp, err := k.ApplyMessageWithConfig(ctx, msg, cfg, true) if err != nil { continue @@ -558,7 +564,10 @@ func (k Keeper) TraceBlock(c context.Context, req *types.QueryTraceBlockRequest) result := types.TxTraceResult{} ethTx := tx.AsTransaction() cfg.TxConfig.TxHash = ethTx.Hash() - cfg.TxConfig.TxIndex = uint(i) + cfg.TxConfig.TxIndex, err = ethermint.SafeUint(i) + if err != nil { + return nil, err + } msg, err := core.TransactionToMessage(ethTx, signer, cfg.BaseFee) if err != nil { result.Error = status.Error(codes.Internal, err.Error()).Error() diff --git a/x/evm/types/key.go b/x/evm/types/key.go index 51b19a469a..719f54df7a 100644 --- a/x/evm/types/key.go +++ b/x/evm/types/key.go @@ -19,6 +19,7 @@ import ( "encoding/binary" "github.com/ethereum/go-ethereum/common" + ethermint "github.com/evmos/ethermint/types" ) const ( @@ -80,14 +81,26 @@ func StateKey(address common.Address, key []byte) []byte { func ObjectGasUsedKey(txIndex int) []byte { var key [1 + 8]byte key[0] = prefixObjectGasUsed - binary.BigEndian.PutUint64(key[1:], uint64(txIndex)) + idx, err := ethermint.SafeIntToUint64(txIndex) + if err != nil { + panic(err) + } + binary.BigEndian.PutUint64(key[1:], idx) return key[:] } func ObjectBloomKey(txIndex, msgIndex int) []byte { var key [1 + 8 + 8]byte key[0] = prefixObjectBloom - binary.BigEndian.PutUint64(key[1:], uint64(txIndex)) - binary.BigEndian.PutUint64(key[9:], uint64(msgIndex)) + value, err := ethermint.SafeIntToUint64(txIndex) + if err != nil { + panic(err) + } + binary.BigEndian.PutUint64(key[1:], value) + value, err = ethermint.SafeIntToUint64(msgIndex) + if err != nil { + panic(err) + } + binary.BigEndian.PutUint64(key[9:], value) return key[:] }