laconicd/x/evm/client/rest/rest.go
yihuang 7d8664043e
impr: support batch eth txs (#901)
* support batch eth tx

Closes: 896

Allow multiple MsgEthereumTx in single tx

* fix transaction receipt api

* fix tx receipt api and accumulate tx gas used

* fix lint

* fix test

* fix rpc test

* cleanup

* fix cumulativeGasUsed and gasUsed

* fix lint

* Update app/ante/eth.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update app/ante/eth.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update rpc/ethereum/backend/utils.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* pr suggestions

* typo

* fix lint

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
2022-01-14 10:37:33 +01:00

117 lines
3.1 KiB
Go

package rest
import (
"context"
"encoding/hex"
"encoding/json"
"errors"
"math/big"
"net/http"
"strings"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client"
clientrest "github.com/cosmos/cosmos-sdk/client/rest"
"github.com/cosmos/cosmos-sdk/types/rest"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types"
feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types"
"github.com/ethereum/go-ethereum/common"
)
// RegisterTxRoutes - Central function to define routes that get registered by the main application
func RegisterTxRoutes(clientCtx client.Context, rtr *mux.Router) {
r := clientrest.WithHTTPDeprecationHeaders(rtr)
r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(clientCtx)).Methods("GET")
r.HandleFunc("/txs", authrest.QueryTxsRequestHandlerFn(clientCtx)).Methods("GET")
r.HandleFunc("/txs/decode", authrest.DecodeTxRequestHandlerFn(clientCtx)).Methods("POST")
}
// QueryTxRequestHandlerFn implements a REST handler that queries a transaction
// by hash in a committed block.
func QueryTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
hashHexStr := vars["hash"]
clientCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, clientCtx, r)
if !ok {
return
}
ethHashPrefix := "0x"
if !strings.HasPrefix(hashHexStr, ethHashPrefix) {
authrest.QueryTxRequestHandlerFn(clientCtx)
return
}
// eth Tx
ethHashPrefixLength := len(ethHashPrefix)
output, err := getEthTransactionByHash(clientCtx, hashHexStr[ethHashPrefixLength:])
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
rest.PostProcessResponseBare(w, clientCtx, output)
}
}
// GetTransactionByHash returns the transaction identified by hash.
func getEthTransactionByHash(clientCtx client.Context, hashHex string) ([]byte, error) {
hash, err := hex.DecodeString(hashHex)
if err != nil {
return nil, err
}
node, err := clientCtx.GetNode()
if err != nil {
return nil, err
}
tx, err := node.Tx(context.Background(), hash, false)
if err != nil {
return nil, err
}
// Can either cache or just leave this out if not necessary
block, err := node.Block(context.Background(), &tx.Height)
if err != nil {
return nil, err
}
client := feemarkettypes.NewQueryClient(clientCtx)
res, err := client.BaseFee(context.Background(), &feemarkettypes.QueryBaseFeeRequest{})
if err != nil {
return nil, err
}
var baseFee *big.Int
if res.BaseFee != nil {
baseFee = res.BaseFee.BigInt()
}
blockHash := common.BytesToHash(block.Block.Header.Hash())
ethTxs, err := rpctypes.RawTxToEthTx(clientCtx, tx.Tx)
if err != nil {
return nil, err
}
height := uint64(tx.Height)
for _, ethTx := range ethTxs {
if common.HexToHash(ethTx.Hash) == common.BytesToHash(hash) {
rpcTx, err := rpctypes.NewRPCTransaction(ethTx.AsTransaction(), blockHash, height, uint64(tx.Index), baseFee)
if err != nil {
return nil, err
}
return json.Marshal(rpcTx)
}
}
return nil, errors.New("eth tx not found")
}