commit 320e5e15501e03a3855bd9e1ef78b8f384e754bb
parent 081d6d437cf328bd7ea8e95fb0cd2a8d33f1dce9
Author: lash <dev@holbrook.no>
Date: Wed, 3 Jul 2024 18:45:45 +0100
Factor out geth specifics
Diffstat:
11 files changed, 337 insertions(+), 312 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,5 +1,15 @@
-all:
+all: direct
+
+direct:
go build -v -o eth-proxy ./cmd/
+geth:
+ go build -v -o eth-proxy ./cmd/geth_proxy/
+
run: all
./eth-proxy
+
+clean:
+ rm -vf eth-proxy
+
+.PHONY: clean
diff --git a/cmd/geth_proxy/main.go b/cmd/geth_proxy/main.go
@@ -0,0 +1,43 @@
+package main
+
+import (
+ "flag"
+ "log"
+ "os"
+ "net/http"
+ "strings"
+
+ "defalsify.org/go-eth-proxy/rpc/geth"
+ "defalsify.org/go-eth-proxy/store/lmdb"
+
+)
+
+
+func main() {
+ dbpath := flag.String("cachepath", ".", "Path to lmdb data")
+ host := flag.String("host", "0.0.0.0", "Remote host")
+ port := flag.String("port", "8545", "Remote path")
+ flag.Parse()
+
+ db, err := lmdb.NewStore(*dbpath)
+ if err != nil {
+ log.Printf("%s", err)
+ os.Exit(1)
+ }
+ defer db.Close()
+
+ h, err := geth.NewGethBackend(db) //svc, flag.Arg(0))
+ if err != nil {
+ log.Printf("%s", err)
+ os.Exit(1)
+ }
+ srv := &http.Server{
+ Handler: h,
+ Addr: strings.Join([]string{*host, *port}, ":"),
+ }
+ err = srv.ListenAndServe()
+ if err != nil {
+ log.Printf("%s", err)
+ os.Exit(1)
+ }
+}
diff --git a/cmd/main.go b/cmd/main.go
@@ -1,44 +0,0 @@
-package main
-
-import (
- "flag"
- "log"
- "os"
- "net/http"
- "strings"
-
- "defalsify.org/go-eth-proxy/proxy"
- "defalsify.org/go-eth-proxy/store/lmdb"
-
-)
-
-
-func main() {
- dbpath := flag.String("cachepath", ".", "Path to lmdb data")
- host := flag.String("host", "0.0.0.0", "Remote host")
- port := flag.String("port", "8545", "Remote path")
- flag.Parse()
-
- db, err := lmdb.NewStore(*dbpath)
- if err != nil {
- log.Printf("%s", err)
- os.Exit(1)
- }
- defer db.Close()
-
- svc := proxy.NewProxyService(db)
- h, err := proxy.NewProxyServer(svc, flag.Arg(0))
- if err != nil {
- log.Printf("%s", err)
- os.Exit(1)
- }
- srv := &http.Server{
- Handler: h,
- Addr: strings.Join([]string{*host, *port}, ":"),
- }
- err = srv.ListenAndServe()
- if err != nil {
- log.Printf("%s", err)
- os.Exit(1)
- }
-}
diff --git a/proxy/rpc.go b/proxy/rpc.go
@@ -1,186 +0,0 @@
-package proxy
-
-import (
- "bytes"
- "encoding/json"
- "io"
- "log"
- "net/http"
- "net/url"
-// "strconv"
-
- "github.com/ethereum/go-ethereum/rpc"
-)
-
-type jsonRpcMsg struct {
- Method string
-
-}
-
-type jsonRpcError struct {
- Code int
-}
-
-type jsonRpcResponse struct {
- Error jsonRpcError
-}
-
-type ProxyServer struct {
- *rpc.Server
- uri *url.URL
-}
-
-type proxyWriter struct {
- header map[string][]string
- status int
- data *bytes.Buffer
- afterHeader bool
-}
-
-
-func (p *proxyWriter) Header() http.Header {
- return p.header
-}
-
-func (p *proxyWriter) Write(b []byte) (int, error) {
- log.Printf("proxyserver %s", b)
- return p.data.Write(b)
-}
-
-func (p *proxyWriter) WriteHeader(status int) {
- p.status = status
-
-}
-
-func (p *proxyWriter) Copy(w http.ResponseWriter) (int, error) {
- c := 0
- l := p.data.Len()
- b := p.data.Bytes()
- for ;c < l; {
- r, err := w.Write(b[c:])
- if err != nil {
- return 0, err
- }
- c += r
- }
- return c, nil
-}
-
-func newProxyWriter() *proxyWriter {
- b := make([]byte, 0, 1024)
- p := &proxyWriter{
- header: make(map[string][]string),
- data: bytes.NewBuffer(b),
- }
- return p
-}
-
-
-
-func NewProxyServer(svc *ProxyService, remoteURI string) (*ProxyServer, error) {
- var uri *url.URL
- var err error
-
- if remoteURI != "" {
- uri, err = url.Parse(remoteURI)
- if err != nil {
- return nil, err
- }
- }
- srv := &ProxyServer{
- Server: rpc.NewServer(),
- uri: uri,
- }
- err = srv.Server.RegisterName("eth", svc)
- if err != nil {
- return nil, err
- }
- return srv, nil
-}
-
-func (s *ProxyServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- //var rrr io.Reader
- msg := jsonRpcMsg{}
- b := make([]byte, r.ContentLength)
- c, err := io.ReadFull(r.Body, b)
- if (err != nil) {
- log.Printf("%s", err)
- r.Body.Close()
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
- r.Body.Close()
- err = json.Unmarshal(b, &msg)
- if (err != nil) {
- log.Printf("%s", err)
- r.Body.Close()
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- rr := bytes.NewReader(b)
- r.Body = io.NopCloser(rr)
-
- for _, k := range([]string{
- "eth_getTransactionByHash",
- }) {
- rw := newProxyWriter()
- if msg.Method == k {
- s.Server.ServeHTTP(rw, r)
- rsp := jsonRpcResponse{}
- err = json.Unmarshal(b, &rsp)
- if (err != nil) {
- log.Printf("%s", err)
- r.Body.Close()
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
- //hd := rw.Header()
- //statusHd := hd["status"]
- //log.Printf("got status %s from proxy", statusHd)
- //if len(statusHd) > 0 && statusHd[0][:1] == "2" {
- if rsp.Error.Code == 0 {
-// statusCode, err := strconv.Atoi(hd["Status"][0])
-// if err != nil {
-// r.Body.Close()
-// w.WriteHeader(http.StatusInternalServerError)
-// return
-// }
-// rw.WriteHeader(statusCode)
- rw.WriteHeader(http.StatusOK)
- rw.Copy(w)
- return
- }
-
- log.Printf("not found in proxy: %s", k)
- rr.Seek(0, io.SeekStart)
- }
- }
-
- if s.uri == nil {
- log.Printf("missing remote side for unproxied method: %s", msg.Method)
- w.WriteHeader(http.StatusBadGateway)
- return
- }
-
- client_req := &http.Request{}
- client_req.Method = "POST"
- client_req.URL = s.uri
- client_req.Body = r.Body
- client_req.ContentLength = int64(c)
- client := &http.Client{}
- res, err := client.Do(client_req)
- if err != nil {
- log.Printf("%s", err)
- r.Body.Close()
- w.WriteHeader(http.StatusBadGateway)
- return
- }
- if res.StatusCode != http.StatusOK {
- v, _ := io.ReadAll(res.Body)
- log.Printf("%s", v)
- }
- w.WriteHeader(res.StatusCode)
- rrr := io.TeeReader(res.Body, w)
- io.ReadAll(rrr)
-}
diff --git a/proxy/service.go b/proxy/service.go
@@ -1,32 +0,0 @@
-package proxy
-
-import (
- "context"
- "log"
-
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/common"
-
- "defalsify.org/go-eth-proxy/store"
-)
-
-type ProxyService struct {
- store store.Store
-}
-
-func NewProxyService(store store.Store) (*ProxyService) {
- return &ProxyService{
- store: store,
- }
-}
-
-func (p *ProxyService) GetTransactionByHash(ctx context.Context, hsh string) (*types.Transaction, error) {
- log.Printf("get tx hash %s", hsh)
- b := common.FromHex(hsh)
- tx, err := p.store.GetTransaction(b)
- if err != nil {
- return nil, err
- }
-
- return tx, nil
-}
diff --git a/proxy/service_test.go b/proxy/service_test.go
@@ -1,49 +0,0 @@
-package proxy
-
-import (
- "log"
- "os"
- "testing"
-
- "github.com/ethereum/go-ethereum/rpc"
- "github.com/ethereum/go-ethereum/core/types"
-
- "defalsify.org/go-eth-proxy/store/lmdb"
-)
-
-func TestProxyServerStart(t *testing.T) {
- var err error
- var tx types.Transaction
- tx_test := "0x60891c813816bb378ee8af428c5eb53b0479c980307d265e4abe39b4efd02e1d"
- //tx_test := "0xffee674f0467b59ce6dd455e9256f95f41118a5bf15a3cedf3d20b5fcbb787a1"
-
- dbpath, dbenv := os.LookupEnv("TEST_LMDB_DIR")
- if !dbenv {
- dbpath = "."
- }
- log.Printf("dbpath %s", dbpath)
-
- db, err := lmdb.NewStore(dbpath)
- if err != nil {
- t.Error(err)
- }
- defer db.Close()
- svc := NewProxyService(db)
-
- srv := rpc.NewServer()
- err = srv.RegisterName("eth", svc)
- if err != nil {
- t.Fatal(err)
- }
- client := rpc.DialInProc(srv)
- mods, err := client.SupportedModules()
- if err != nil {
- t.Fatal(err)
- }
- t.Logf("mods %s", mods)
- err = client.Call(&tx, "eth_getTransactionByHash", tx_test)
- if err != nil {
- t.Fatal(err)
- }
- t.Logf("tx %v", tx_test)
-}
diff --git a/rpc/geth/geth.go b/rpc/geth/geth.go
@@ -0,0 +1,22 @@
+package geth
+
+import (
+ "net/http"
+
+ gethrpc "github.com/ethereum/go-ethereum/rpc"
+
+ "defalsify.org/go-eth-proxy/store"
+)
+
+func NewGethBackend(db store.Store) (http.Handler, error) {
+ var err error
+
+ svc := NewProxyService(db)
+ srv := gethrpc.NewServer()
+ err = srv.RegisterName("eth", svc)
+ if err != nil {
+ return nil, err
+ }
+ return srv, nil
+
+}
diff --git a/rpc/geth/service.go b/rpc/geth/service.go
@@ -0,0 +1,32 @@
+package geth
+
+import (
+ "context"
+ "log"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/common"
+
+ "defalsify.org/go-eth-proxy/store"
+)
+
+type ProxyService struct {
+ store store.Store
+}
+
+func NewProxyService(store store.Store) (*ProxyService) {
+ return &ProxyService{
+ store: store,
+ }
+}
+
+func (p *ProxyService) GetTransactionByHash(ctx context.Context, hsh string) (*types.Transaction, error) {
+ log.Printf("get tx hash %s", hsh)
+ b := common.FromHex(hsh)
+ tx, err := p.store.GetTransaction(b)
+ if err != nil {
+ return nil, err
+ }
+
+ return tx, nil
+}
diff --git a/rpc/geth/service_test.go b/rpc/geth/service_test.go
@@ -0,0 +1,49 @@
+package geth
+
+import (
+ "log"
+ "os"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/rpc"
+ "github.com/ethereum/go-ethereum/core/types"
+
+ "defalsify.org/go-eth-proxy/store/lmdb"
+)
+
+func TestProxyServerStart(t *testing.T) {
+ var err error
+ var tx types.Transaction
+ tx_test := "0x60891c813816bb378ee8af428c5eb53b0479c980307d265e4abe39b4efd02e1d"
+ //tx_test := "0xffee674f0467b59ce6dd455e9256f95f41118a5bf15a3cedf3d20b5fcbb787a1"
+
+ dbpath, dbenv := os.LookupEnv("TEST_LMDB_DIR")
+ if !dbenv {
+ dbpath = "."
+ }
+ log.Printf("dbpath %s", dbpath)
+
+ db, err := lmdb.NewStore(dbpath)
+ if err != nil {
+ t.Error(err)
+ }
+ defer db.Close()
+ svc := NewProxyService(db)
+
+ srv := rpc.NewServer()
+ err = srv.RegisterName("eth", svc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ client := rpc.DialInProc(srv)
+ mods, err := client.SupportedModules()
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("mods %s", mods)
+ err = client.Call(&tx, "eth_getTransactionByHash", tx_test)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("tx %v", tx_test)
+}
diff --git a/rpc/rpc.go b/rpc/rpc.go
@@ -0,0 +1,179 @@
+package rpc
+
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "log"
+ "net/http"
+ "net/url"
+// "strconv"
+)
+
+type jsonRpcMsg struct {
+ Method string
+
+}
+
+type jsonRpcError struct {
+ Code int
+}
+
+type jsonRpcResponse struct {
+ Error jsonRpcError
+}
+
+type ProxyServer struct {
+ Server http.Handler
+ uri *url.URL
+}
+
+type proxyWriter struct {
+ header map[string][]string
+ status int
+ data *bytes.Buffer
+ afterHeader bool
+}
+
+
+func (p *proxyWriter) Header() http.Header {
+ return p.header
+}
+
+func (p *proxyWriter) Write(b []byte) (int, error) {
+ log.Printf("proxyserver %s", b)
+ return p.data.Write(b)
+}
+
+func (p *proxyWriter) WriteHeader(status int) {
+ p.status = status
+
+}
+
+func (p *proxyWriter) Copy(w http.ResponseWriter) (int, error) {
+ c := 0
+ l := p.data.Len()
+ b := p.data.Bytes()
+ for ;c < l; {
+ r, err := w.Write(b[c:])
+ if err != nil {
+ return 0, err
+ }
+ c += r
+ }
+ return c, nil
+}
+
+func newProxyWriter() *proxyWriter {
+ b := make([]byte, 0, 1024)
+ p := &proxyWriter{
+ header: make(map[string][]string),
+ data: bytes.NewBuffer(b),
+ }
+ return p
+}
+
+func NewProxyServer(backend http.Handler, remoteURI string) (*ProxyServer, error) {
+ var uri *url.URL
+ var err error
+
+ if remoteURI != "" {
+ uri, err = url.Parse(remoteURI)
+ if err != nil {
+ return nil, err
+ }
+ }
+ srv := &ProxyServer{
+ Server: backend,
+ uri: uri,
+ }
+ return srv, nil
+}
+
+func (s *ProxyServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ //var rrr io.Reader
+ msg := jsonRpcMsg{}
+ b := make([]byte, r.ContentLength)
+ c, err := io.ReadFull(r.Body, b)
+ if (err != nil) {
+ log.Printf("%s", err)
+ r.Body.Close()
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ r.Body.Close()
+ err = json.Unmarshal(b, &msg)
+ if (err != nil) {
+ log.Printf("%s", err)
+ r.Body.Close()
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ rr := bytes.NewReader(b)
+ r.Body = io.NopCloser(rr)
+
+ for _, k := range([]string{
+ "eth_getTransactionByHash",
+ }) {
+ rw := newProxyWriter()
+ if msg.Method == k {
+ s.Server.ServeHTTP(rw, r)
+ rsp := jsonRpcResponse{}
+ err = json.Unmarshal(b, &rsp)
+ if (err != nil) {
+ log.Printf("%s", err)
+ r.Body.Close()
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ //hd := rw.Header()
+ //statusHd := hd["status"]
+ //log.Printf("got status %s from proxy", statusHd)
+ //if len(statusHd) > 0 && statusHd[0][:1] == "2" {
+ if rsp.Error.Code == 0 {
+// statusCode, err := strconv.Atoi(hd["Status"][0])
+// if err != nil {
+// r.Body.Close()
+// w.WriteHeader(http.StatusInternalServerError)
+// return
+// }
+// rw.WriteHeader(statusCode)
+ rw.WriteHeader(http.StatusOK)
+ rw.Copy(w)
+ return
+ }
+
+ log.Printf("not found in proxy: %s", k)
+ rr.Seek(0, io.SeekStart)
+ }
+ }
+
+ if s.uri == nil {
+ log.Printf("missing remote side for unproxied method: %s", msg.Method)
+ w.WriteHeader(http.StatusBadGateway)
+ return
+ }
+
+ client_req := &http.Request{}
+ client_req.Method = "POST"
+ client_req.URL = s.uri
+ client_req.Body = r.Body
+ client_req.ContentLength = int64(c)
+ client := &http.Client{}
+ res, err := client.Do(client_req)
+ if err != nil {
+ log.Printf("%s", err)
+ r.Body.Close()
+ w.WriteHeader(http.StatusBadGateway)
+ return
+ }
+ if res.StatusCode != http.StatusOK {
+ v, _ := io.ReadAll(res.Body)
+ log.Printf("%s", v)
+ }
+ w.WriteHeader(res.StatusCode)
+ rrr := io.TeeReader(res.Body, w)
+ io.ReadAll(rrr)
+}
diff --git a/store/store.go b/store/store.go
@@ -8,3 +8,4 @@ type Store interface {
GetTransaction(b []byte) (*types.Transaction, error)
Close()
}
+