From 9ecd264ae0e8c6ace10abe3bc45ab8d3c29dc10f Mon Sep 17 00:00:00 2001 From: Pierre <974741468@qq.com> Date: Mon, 11 Jan 2021 21:31:30 +0800 Subject: [PATCH] Add API for compatible query of two types of transactions (#683) * Add API for compatible query of two types of transactions * format code * optimize code * optimize code * format code * optimize code * add error handling Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> --- rpc/config.go | 8 ++-- x/evm/client/rest/rest.go | 98 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 x/evm/client/rest/rest.go diff --git a/rpc/config.go b/rpc/config.go index 12125449..f3fc9205 100644 --- a/rpc/config.go +++ b/rpc/config.go @@ -6,21 +6,19 @@ import ( "os" "strings" - "github.com/spf13/viper" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" "github.com/cosmos/cosmos-sdk/client/lcd" "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" - authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" - "github.com/cosmos/ethermint/app" "github.com/cosmos/ethermint/crypto/ethsecp256k1" "github.com/cosmos/ethermint/crypto/hd" "github.com/cosmos/ethermint/rpc/websockets" + evmrest "github.com/cosmos/ethermint/x/evm/client/rest" "github.com/ethereum/go-ethereum/rpc" + "github.com/spf13/viper" ) const ( @@ -75,7 +73,7 @@ func RegisterRoutes(rs *lcd.RestServer) { // Register all other Cosmos routes client.RegisterRoutes(rs.CliCtx, rs.Mux) - authrest.RegisterTxRoutes(rs.CliCtx, rs.Mux) + evmrest.RegisterRoutes(rs.CliCtx, rs.Mux) app.ModuleBasics.RegisterRESTRoutes(rs.CliCtx, rs.Mux) // start websockets server diff --git a/x/evm/client/rest/rest.go b/x/evm/client/rest/rest.go new file mode 100644 index 00000000..7658faa9 --- /dev/null +++ b/x/evm/client/rest/rest.go @@ -0,0 +1,98 @@ +package rest + +import ( + "encoding/hex" + "encoding/json" + "net/http" + "strings" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/types/rest" + authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + rpctypes "github.com/cosmos/ethermint/rpc/types" + "github.com/ethereum/go-ethereum/common" + "github.com/gorilla/mux" +) + +// RegisterRoutes - Central function to define routes that get registered by the main application +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { + r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/txs", authrest.QueryTxsRequestHandlerFn(cliCtx)).Methods("GET") // default from auth + r.HandleFunc("/txs", authrest.BroadcastTxRequest(cliCtx)).Methods("POST") // default from auth + r.HandleFunc("/txs/encode", authrest.EncodeTxRequestHandlerFn(cliCtx)).Methods("POST") // default from auth + r.HandleFunc("/txs/decode", authrest.DecodeTxRequestHandlerFn(cliCtx)).Methods("POST") // default from auth +} + +func QueryTxRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + hashHexStr := vars["hash"] + + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + ethHashPrefix := "0x" + if strings.HasPrefix(hashHexStr, ethHashPrefix) { + // eth Tx + ethHashPrefixLength := len(ethHashPrefix) + output, err := getEthTransactionByHash(cliCtx, hashHexStr[ethHashPrefixLength:]) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + rest.PostProcessResponseBare(w, cliCtx, output) + return + } + + output, err := utils.QueryTx(cliCtx, hashHexStr) + if err != nil { + if strings.Contains(err.Error(), hashHexStr) { + rest.WriteErrorResponse(w, http.StatusNotFound, err.Error()) + return + } + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + rest.PostProcessResponseBare(w, cliCtx, output) + } + +} + +// GetTransactionByHash returns the transaction identified by hash. +func getEthTransactionByHash(cliCtx context.CLIContext, hashHex string) ([]byte, error) { + hash, err := hex.DecodeString(hashHex) + if err != nil { + return nil, err + } + node, err := cliCtx.GetNode() + if err != nil { + return nil, err + } + tx, err := node.Tx(hash, false) + if err != nil { + return nil, err + } + + // Can either cache or just leave this out if not necessary + block, err := node.Block(&tx.Height) + if err != nil { + return nil, err + } + + blockHash := common.BytesToHash(block.Block.Header.Hash()) + + ethTx, err := rpctypes.RawTxToEthTx(cliCtx, tx.Tx) + if err != nil { + return nil, err + } + + height := uint64(tx.Height) + res, err := rpctypes.NewTransaction(ethTx, common.BytesToHash(tx.Tx.Hash()), blockHash, height, uint64(tx.Index)) + if err != nil { + return nil, err + } + return json.Marshal(res) +}