Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@

# Dependency directories (remove the comment below to include it)
# vendor/
bin/
.idea

node_modules
46 changes: 45 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,45 @@
# eth-proxy
# ethereum_proxy
ethereum_proxy

```
go build -o ./bin/ethereum_proxy ./cmd
```

```asciidoc
export PROXY_HOST=127.0.0.1:37101
export PROXY_PORT=5000

./bin/ethereum_proxy
```

```
curl -H "Content-Type:application/json" -d '{"jsonrpc":"2.0","method":"eth_estimateGas","params":[],"id":1}' 127.0.0.1:8545

curl -H "Content-Type:application/json" -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' 127.0.0.1:8545

curl -H "Content-Type:application/json" -d '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x3e8", true],"id":1}' 127.0.0.1:8545

// dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN => 0x93F86A462A3174C7AD1281BCF400A9F18D244E06
curl -H "Content-Type:application/json" -d '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x93F86A462A3174C7AD1281BCF400A9F18D244E06", "latest"],"id":1}' 127.0.0.1:8545

curl -H "Content-Type:application/json" -d '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["0x27f55958c8c1656699563b2f7bf3e3ad4e4476f5526d41065a9efa6e50b082b5"],"id":1}' 127.0.0.1:8545

// If true it returns the full transaction objects, if false only the hashes of the transactions.
curl -H "Content-Type:application/json" -d '{"jsonrpc":"2.0","method":"eth_getBlockByHash","params":["0x494181a8688c1550e8deea48e1eca750790169cf1b654089f88b126e4624c33e",false],"id":1}' 127.0.0.1:8545

// contractName => 0x
curl -H "Content-Type:application/json" -d '{"jsonrpc":"2.0","method":"eth_getCode","params":["0x313131312D2D2D2D2D476574436F646554657372"],"id":1}' 127.0.0.1:8545

curl -H "Content-Type:application/json" -d '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0xa46a766ce422e1e1a9827efe6989eeacc82a2352765287fe557497465751d9ab"],"id":1}' 127.0.0.1:8545

curl -H "Content-Type:application/json" -d '{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock":"0","toBlock":"13672"}],"id":1}' 127.0.0.1:8545

curl -H "Content-Type:application/json" -d '{"jsonrpc":"2.0","method":"eth_newFilter","params":[{"fromBlock":"0","toBlock":"13672"}],"id":1}' 127.0.0.1:8545

curl -H "Content-Type:application/json" -d '{"jsonrpc":"2.0","method":"eth_uninstallFilter","params":["0x282b21d7db0eaedb137e25b56337666d"],"id":1}' 127.0.0.1:8545

curl -H "Content-Type:application/json" -d '{"jsonrpc":"2.0","method":"eth_getFilterLogs","params":["0xdcccf7c1c88df9e5e8249f8caf0861a"],"id":1}' 127.0.0.1:8545


```

125 changes: 125 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright (c) 2021. Baidu Inc. All Rights Reserved.
*/

package main

import (
"fmt"
"os"
"os/signal"
"syscall"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.uber.org/zap"

"github.com/xuperchain/eth_proxy"
)

var host string
var port int
var account string
var keyPath string

// InitFlags sets up the flags and environment variables for Proxy
//func initFlags() {
//}

// Viper takes care of precedence of Flags and Environment variables
// Flag values are taken over environment variables
// Both CCID and Port have defaults so do not need to be provided.
//func checkFlags() error {
// host = viper.GetString("host")
// if host == "" {
// return fmt.Errorf("Missing host. Please use flag --host or set PROXY_HOST")
// }
//
// port = viper.GetInt("port")
// return nil
//}

// Runs Proxy
// Will exit gracefully for errors and signal interrupts
func runProxy(cmd *cobra.Command, args []string) error {

rawLogger, err := zap.NewDevelopment()
if err != nil {
return fmt.Errorf("Failed to create logger: %s\n", err)
}
logger := rawLogger.Named("proxy").Sugar()

ethService, err := eth_proxy.NewEthService(&eth_proxy.EthServiceConfig{
Host: host,
ContractAccount: account,
KeyPath: keyPath,
})
if err != nil {
return err
}

proxy := eth_proxy.NewEthereumProxy(ethService, port)

errChan := make(chan error, 1)
go func() {
errChan <- proxy.Start()
}()
logger.Infow("Starting Proxy", "port", port)

signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)

select {
case err = <-errChan:
fmt.Println(err)
// TODO add error check
case <-signalChan:
logger.Info("Received termination signal")
err = proxy.Shutdown()
}

if err != nil {
logger.Infow("Proxy exited with error", "error", err)
return err
}
logger.Info("Proxy exited")
return nil
}

func main() {
var proxyCmd = &cobra.Command{
Use: "proxy",
Short: "proxy is a web3 provider used to interact with the EVM chaincode on a XuperChain Network. The flags provided will be honored over the corresponding environment variables.",
Long: "proxy is a web3 provider used to interact with the EVM chaincode on a XuperChain Network. The flags provided will be honored over the corresponding environment variables.",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {

// At this point all of our flags have been validated
// Usage no longer needs to be provided for the errors that follow
cmd.SilenceUsage = false
return runProxy(cmd, args)
},
}
viper.SetEnvPrefix("PROXY")
viper.BindEnv("host")
viper.BindEnv("port")
viper.BindEnv("account")

proxyCmd.PersistentFlags().StringVarP(&host, "host", "t", "127.0.0.1:37101",
"Path to a compatible Fabric SDK Go config file. This flag is required if PROXY_HOST is not set.")
viper.BindPFlag("config", proxyCmd.PersistentFlags().Lookup("host"))

proxyCmd.PersistentFlags().IntVarP(&port, "port", "p", 8545,
"Port that Proxy will be running on. The listening port can also be set by the PROXY_PORT environment variable.")
viper.BindPFlag("port", proxyCmd.PersistentFlags().Lookup("port"))

proxyCmd.PersistentFlags().StringVar(&account, "account", "XC1234567890123456@xuper", "account to send transaction")
viper.BindPFlag("account", proxyCmd.PersistentFlags().Lookup("account"))

proxyCmd.PersistentFlags().StringVar(&keyPath, "key", "data/keys", "key path")
viper.BindPFlag("key", proxyCmd.PersistentFlags().Lookup("key"))

if proxyCmd.Execute() != nil {
os.Exit(1)
}
}
51 changes: 51 additions & 0 deletions codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2021. Baidu Inc. All Rights Reserved.
*/

package eth_proxy

import (
"fmt"
"net/http"
"strings"

"github.com/gorilla/rpc/v2"
"github.com/gorilla/rpc/v2/json2"
)

type rpcCodec struct {
codec *json2.Codec
}

type rpcCodecRequest struct {
rpc.CodecRequest
}

func NewRPCCodec() rpc.Codec {
return &rpcCodec{codec: json2.NewCodec()}
}

func (c *rpcCodec) NewRequest(r *http.Request) rpc.CodecRequest {
return &rpcCodecRequest{c.codec.NewRequest(r)}
}

/* Gorilla RPC expects methods follow Go style of service.Method, where service is an object that has the method `Method`.
Ethereum JSON RPC expect methods to follow service_method
String conversion is necessary to change service_method to service.Method to meet Gorilla RPC requirements
*/
func (r *rpcCodecRequest) Method() (string, error) {

m, err := r.CodecRequest.Method()
if err != nil {
return "", err
}
method := strings.Split(m, "_")
if len(method) > 2 {
return "", fmt.Errorf("Received a malformed method: %s", method)
}
if method[1] != "version" && method[1] != "accounts" && method[1] != "getBalance" {
fmt.Println(method)
}
modifiedMethod := fmt.Sprintf("%s.%s", method[0], strings.Title(method[1]))
return modifiedMethod, nil
}
1 change: 1 addition & 0 deletions data/keys/address
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TeyyPLpp9L7QAcxHangtcHTu7HUZ6iydY
1 change: 1 addition & 0 deletions data/keys/private.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"Curvname":"P-256","X":36505150171354363400464126431978257855318414556425194490762274938603757905292,"Y":79656876957602994269528255245092635964473154458596947290316223079846501380076,"D":111497060296999106528800133634901141644446751975433315540300236500052690483486}
1 change: 1 addition & 0 deletions data/keys/public.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"Curvname":"P-256","X":36505150171354363400464126431978257855318414556425194490762274938603757905292,"Y":79656876957602994269528255245092635964473154458596947290316223079846501380076}
60 changes: 60 additions & 0 deletions ethereum_proxy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2021. Baidu Inc. All Rights Reserved.
*/

package eth_proxy

import (
"context"
"fmt"
"net/http"

"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/gorilla/rpc/v2"
)

type EthereumProxy struct {
RPCServer *rpc.Server
HTTPServer *http.Server
}

func NewEthereumProxy(service EthService, port int) *EthereumProxy {
rpcServer := rpc.NewServer()

proxy := &EthereumProxy{
RPCServer: rpcServer,
}

rpcServer.RegisterCodec(NewRPCCodec(), "application/json")
msg := "this panic indicates a programming error, and is unreachable"
if err := rpcServer.RegisterService(service, "eth"); err != nil {
panic(msg)
}
if err := rpcServer.RegisterService(&NetService{}, "net"); err != nil {
panic(msg)
}

r := mux.NewRouter()
r.Handle("/", proxy.RPCServer)

allowedHeaders := handlers.AllowedHeaders([]string{"Origin", "Content-Type"})
allowedOrigins := handlers.AllowedOrigins([]string{"*"})
allowedMethods := handlers.AllowedMethods([]string{"POST"})

proxy.HTTPServer = &http.Server{
Handler: handlers.CORS(allowedHeaders, allowedOrigins, allowedMethods)(r),
Addr: fmt.Sprintf(":%d", port)}
return proxy
}

func (p *EthereumProxy) Start() error {
return p.HTTPServer.ListenAndServe()
}

func (p *EthereumProxy) Shutdown() error {
if p.HTTPServer != nil {
return p.HTTPServer.Shutdown(context.Background())
}
return nil
}
52 changes: 52 additions & 0 deletions ethereum_proxy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package eth_proxy

import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"testing"
)

func TestProxy(t *testing.T) {
type Params struct {
Data string
}
data := struct {
JSONRPC string
Method string
Params string
}{
JSONRPC: "2.0",
Method: "eth_sendRawTransaction",
Params: "0xf867808082520894f97798df751deb4b6e39d4cf998ee7cd4dcb9acc880de0b6b3a76400008025a0f0d2396973296cd6a71141c974d4a851f5eae8f08a8fba2dc36a0fef9bd6440ca0171995aa750d3f9f8e4d0eac93ff67634274f3c5acf422723f49ff09a6885422",
}
datas, err := json.Marshal(data)
if err != nil {
{
t.Error(err)
}
}
r := bytes.NewReader(datas)
req, err := http.NewRequest("POST", "http://127.0.0.1:8545", r)
if err != nil {
t.Error(err)
return
}
req.Header.Add("Content-Type", "application/json")
//headers := http.Header{
// "Content-Type": []string{":application/json"},
//}
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
t.Error(err)
}
resp1, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Error(err)
return
}
t.Log(resp.Status)
t.Log("resp:", string(resp1))
}
Loading