diff --git a/Dockerfile b/Dockerfile index 49ff124..09e1a9e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,14 +28,12 @@ RUN apk add alpine-sdk WORKDIR /wd COPY ["go.mod","go.sum","/wd/"] COPY cmd cmd -RUN go build -o rpcdaemon ./cmd/rpcdaemon -RUN go build -o server ./cmd/server +RUN go build -o otter ./cmd/otter FROM alpine:3.15.0 RUN apk add alpine-sdk WORKDIR /wd -COPY --from=gobuilder /wd/rpcdaemon /usr/bin/rpcdaemon -COPY --from=gobuilder /wd/server /usr/bin/server +COPY --from=gobuilder /wd/otter /usr/bin/otter COPY --from=builder /otterscan-build/dist /wd/dist COPY --from=logobuilder /assets /wd/dist diff --git a/cmd/rpcdaemon/README.md b/cmd/otter/README.md similarity index 100% rename from cmd/rpcdaemon/README.md rename to cmd/otter/README.md diff --git a/cmd/rpcdaemon/cli/config.go b/cmd/otter/cli/config.go similarity index 80% rename from cmd/rpcdaemon/cli/config.go rename to cmd/otter/cli/config.go index 52fb604..f539829 100644 --- a/cmd/rpcdaemon/cli/config.go +++ b/cmd/otter/cli/config.go @@ -2,17 +2,15 @@ package cli import ( "context" - "crypto/rand" "encoding/binary" - "errors" "fmt" "net" "net/http" - "os" "path/filepath" "strings" "time" + "github.com/go-chi/chi/v5" "github.com/ledgerwatch/erigon-lib/common/dir" libstate "github.com/ledgerwatch/erigon-lib/state" "github.com/ledgerwatch/erigon/eth/ethconfig" @@ -20,9 +18,9 @@ import ( "github.com/ledgerwatch/erigon/turbo/debug" "github.com/ledgerwatch/erigon/turbo/logging" - "github.com/wmitsuda/otterscan/cmd/rpcdaemon/cli/httpcfg" - "github.com/wmitsuda/otterscan/cmd/rpcdaemon/health" - "github.com/wmitsuda/otterscan/cmd/rpcdaemon/rpcservices" + "github.com/wmitsuda/otterscan/cmd/otter/cli/httpcfg" + "github.com/wmitsuda/otterscan/cmd/otter/health" + "github.com/wmitsuda/otterscan/cmd/otter/rpcservices" "github.com/ledgerwatch/erigon-lib/direct" "github.com/ledgerwatch/erigon-lib/gointerfaces" @@ -35,8 +33,6 @@ import ( "github.com/ledgerwatch/erigon-lib/kv/remotedb" "github.com/ledgerwatch/erigon-lib/kv/remotedbserver" "github.com/ledgerwatch/erigon/cmd/utils" - "github.com/ledgerwatch/erigon/common" - "github.com/ledgerwatch/erigon/common/hexutil" "github.com/ledgerwatch/erigon/common/paths" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/node" @@ -57,14 +53,17 @@ import ( ) var rootCmd = &cobra.Command{ - Use: "rpcdaemon", - Short: "rpcdaemon is JSON RPC server that connects to Erigon node for remote DB access", + Use: "otter", + Short: "otterscan is a chain explorer that can also host a custom JSON RPC server that connects to an Erigon node", } func RootCommand() (*cobra.Command, *httpcfg.HttpCfg) { utils.CobraFlags(rootCmd, debug.Flags, utils.MetricFlags, logging.Flags) - cfg := &httpcfg.HttpCfg{Enabled: true, StateCache: kvcache.DefaultCoherentConfig} + cfg := &httpcfg.HttpCfg{} + cfg.Enabled = true + cfg.StateCache = kvcache.DefaultCoherentConfig + rootCmd.PersistentFlags().StringVar(&cfg.PrivateApiAddr, "private.api.addr", "127.0.0.1:9090", "private api network address, for example: 127.0.0.1:9090") rootCmd.PersistentFlags().StringVar(&cfg.DataDir, "datadir", "", "path to Erigon working directory") rootCmd.PersistentFlags().StringVar(&cfg.HttpListenAddress, "http.addr", nodecfg.DefaultHTTPHost, "HTTP-RPC server listening interface") @@ -105,6 +104,16 @@ func RootCommand() (*cobra.Command, *httpcfg.HttpCfg) { panic(err) } + // otterscan server setting + + rootCmd.PersistentFlags().BoolVar(&cfg.OtsServerDisable, "ots.server.addr", false, "disable ots server to run rpc daemon only") + rootCmd.PersistentFlags().StringVar(&cfg.OtsStaticDir, "ots.static.dir", "./dist", "dir to serve static files from") + rootCmd.PersistentFlags().BoolVar(&cfg.DisableRpcDaemon, "disable.rpc.daemon", false, "dont run rpc daemon, for use when specifying external rtpc daemon") + + rootCmd.PersistentFlags().StringVar(&cfg.OtsBeaconApiUrl, "ots.beaconapi.url", "http://localhost:3500", "where the website will make request for beacon api") + rootCmd.PersistentFlags().StringVar(&cfg.OtsRpcDaemonUrl, "ots.rpcdaemon.url", "/rpc", "where the website will make request for beacon api") + rootCmd.PersistentFlags().StringVar(&cfg.OtsExternalAssetUrl, "ots.externalasset.url", "/", "where website will make request for assets") + rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { if err := debug.SetupCobra(cmd); err != nil { return err @@ -442,23 +451,14 @@ func RemoteServices(ctx context.Context, cfg httpcfg.HttpCfg, logger log.Logger, return db, borDb, eth, txPool, mining, stateCache, blockReader, ff, agg, err } -func StartRpcServer(ctx context.Context, cfg httpcfg.HttpCfg, rpcAPI []rpc.API, authAPI []rpc.API) error { - if len(authAPI) > 0 { - engineInfo, err := startAuthenticatedRpcServer(cfg, authAPI) - if err != nil { - return err - } - go stopAuthenticatedRpcServer(ctx, engineInfo) - } - +func StartRpcServer(ctx context.Context, r chi.Router, cfg httpcfg.HttpCfg, rpcAPI []rpc.API) error { if cfg.Enabled { - return startRegularRpcServer(ctx, cfg, rpcAPI) + return startServer(ctx, r, cfg, rpcAPI) } - return nil } -func startRegularRpcServer(ctx context.Context, cfg httpcfg.HttpCfg, rpcAPI []rpc.API) error { +func startServer(ctx context.Context, r chi.Router, cfg httpcfg.HttpCfg, rpcAPI []rpc.API) error { // register apis and create handler stack httpEndpoint := fmt.Sprintf("%s:%d", cfg.HttpListenAddress, cfg.HttpPort) @@ -500,126 +500,60 @@ func startRegularRpcServer(ctx context.Context, cfg httpcfg.HttpCfg, rpcAPI []rp if err != nil { return err } - - listener, _, err := node.StartHTTPEndpoint(httpEndpoint, cfg.HTTPTimeouts, apiHandler) + r.Mount("/rpc", apiHandler) + listener, _, err := node.StartHTTPEndpoint(httpEndpoint, cfg.HTTPTimeouts, r) if err != nil { return fmt.Errorf("could not start RPC api: %w", err) } - info := []interface{}{"url", httpEndpoint, "ws", cfg.WebsocketEnabled, + info := &[]interface{}{"url", httpEndpoint, "ws", cfg.WebsocketEnabled, "ws.compression", cfg.WebsocketCompression, "grpc", cfg.GRPCServerEnabled} - - var ( - healthServer *grpcHealth.Server - grpcServer *grpc.Server - grpcListener net.Listener - grpcEndpoint string - ) if cfg.GRPCServerEnabled { - grpcEndpoint = fmt.Sprintf("%s:%d", cfg.GRPCListenAddress, cfg.GRPCPort) - if grpcListener, err = net.Listen("tcp", grpcEndpoint); err != nil { - return fmt.Errorf("could not start GRPC listener: %w", err) + startGrpcServer(ctx, info, cfg) + if err != nil { + return fmt.Errorf("could not start GRPC api: %w", err) } - grpcServer = grpc.NewServer() - if cfg.GRPCHealthCheckEnabled { - healthServer = grpcHealth.NewServer() - grpc_health_v1.RegisterHealthServer(grpcServer, healthServer) - } - go grpcServer.Serve(grpcListener) - info = append(info, "grpc.port", cfg.GRPCPort) } - - log.Info("HTTP endpoint opened", info...) - + log.Info("HTTP endpoint opened", *info...) defer func() { srv.Stop() shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() _ = listener.Shutdown(shutdownCtx) log.Info("HTTP endpoint closed", "url", httpEndpoint) - - if cfg.GRPCServerEnabled { - if cfg.GRPCHealthCheckEnabled { - healthServer.Shutdown() - } - grpcServer.GracefulStop() - _ = grpcListener.Close() - log.Info("GRPC endpoint closed", "url", grpcEndpoint) - } }() <-ctx.Done() log.Info("Exiting...") return nil } -type engineInfo struct { - Srv *rpc.Server - EngineSrv *rpc.Server - EngineListener *http.Server - EngineHttpEndpoint string -} - -func startAuthenticatedRpcServer(cfg httpcfg.HttpCfg, rpcAPI []rpc.API) (*engineInfo, error) { - log.Trace("TraceRequests = %t\n", cfg.TraceRequests) - srv := rpc.NewServer(cfg.RpcBatchConcurrency, cfg.TraceRequests, cfg.RpcStreamingDisable) - - engineListener, engineSrv, engineHttpEndpoint, err := createEngineListener(cfg, rpcAPI) - if err != nil { - return nil, fmt.Errorf("could not start RPC api for engine: %w", err) +func startGrpcServer(ctx context.Context, info *[]any, cfg httpcfg.HttpCfg) (err error) { + var ( + healthServer *grpcHealth.Server + grpcServer *grpc.Server + grpcListener net.Listener + grpcEndpoint string + ) + grpcEndpoint = fmt.Sprintf("%s:%d", cfg.GRPCListenAddress, cfg.GRPCPort) + if grpcListener, err = net.Listen("tcp", grpcEndpoint); err != nil { + return fmt.Errorf("could not start GRPC listener: %w", err) } - return &engineInfo{Srv: srv, EngineSrv: engineSrv, EngineListener: engineListener, EngineHttpEndpoint: engineHttpEndpoint}, nil -} + grpcServer = grpc.NewServer() + if cfg.GRPCHealthCheckEnabled { + healthServer = grpcHealth.NewServer() + grpc_health_v1.RegisterHealthServer(grpcServer, healthServer) + } + go grpcServer.Serve(grpcListener) + *info = append(*info, "grpc.port", cfg.GRPCPort) -func stopAuthenticatedRpcServer(ctx context.Context, engineInfo *engineInfo) { defer func() { - engineInfo.Srv.Stop() - if engineInfo.EngineSrv != nil { - engineInfo.EngineSrv.Stop() - } - shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - if engineInfo.EngineListener != nil { - _ = engineInfo.EngineListener.Shutdown(shutdownCtx) - log.Info("Engine HTTP endpoint close", "url", engineInfo.EngineHttpEndpoint) + if cfg.GRPCHealthCheckEnabled { + healthServer.Shutdown() } + grpcServer.GracefulStop() + _ = grpcListener.Close() + log.Info("GRPC endpoint closed", "url", grpcEndpoint) }() - <-ctx.Done() - log.Info("Exiting Engine...") -} - -// isWebsocket checks the header of a http request for a websocket upgrade request. -func isWebsocket(r *http.Request) bool { - return strings.EqualFold(r.Header.Get("Upgrade"), "websocket") && - strings.Contains(strings.ToLower(r.Header.Get("Connection")), "upgrade") -} - -// obtainJWTSecret loads the jwt-secret, either from the provided config, -// or from the default location. If neither of those are present, it generates -// a new secret and stores to the default location. -func obtainJWTSecret(cfg httpcfg.HttpCfg) ([]byte, error) { - // try reading from file - log.Info("Reading JWT secret", "path", cfg.JWTSecretPath) - // If we run the rpcdaemon and datadir is not specified we just use jwt.hex in current directory. - if len(cfg.JWTSecretPath) == 0 { - cfg.JWTSecretPath = "jwt.hex" - } - if data, err := os.ReadFile(cfg.JWTSecretPath); err == nil { - jwtSecret := common.FromHex(strings.TrimSpace(string(data))) - if len(jwtSecret) == 32 { - return jwtSecret, nil - } - log.Error("Invalid JWT secret", "path", cfg.JWTSecretPath, "length", len(jwtSecret)) - return nil, errors.New("invalid JWT secret") - } - // Need to generate one - jwtSecret := make([]byte, 32) - rand.Read(jwtSecret) - - if err := os.WriteFile(cfg.JWTSecretPath, []byte(hexutil.Encode(jwtSecret)), 0600); err != nil { - return nil, err - } - log.Info("Generated JWT secret", "path", cfg.JWTSecretPath) - return jwtSecret, nil + return nil } func createHandler(cfg httpcfg.HttpCfg, apiList []rpc.API, httpHandler http.Handler, wsHandler http.Handler, jwtSecret []byte) (http.Handler, error) { @@ -643,36 +577,8 @@ func createHandler(cfg httpcfg.HttpCfg, apiList []rpc.API, httpHandler http.Hand return handler, nil } -func createEngineListener(cfg httpcfg.HttpCfg, engineApi []rpc.API) (*http.Server, *rpc.Server, string, error) { - engineHttpEndpoint := fmt.Sprintf("%s:%d", cfg.AuthRpcHTTPListenAddress, cfg.AuthRpcPort) - - engineSrv := rpc.NewServer(cfg.RpcBatchConcurrency, cfg.TraceRequests, true) - - if err := node.RegisterApisFromWhitelist(engineApi, nil, engineSrv, true); err != nil { - return nil, nil, "", fmt.Errorf("could not start register RPC engine api: %w", err) - } - - jwtSecret, err := obtainJWTSecret(cfg) - if err != nil { - return nil, nil, "", err - } - - wsHandler := engineSrv.WebsocketHandler([]string{"*"}, jwtSecret, cfg.WebsocketCompression) - - engineHttpHandler := node.NewHTTPHandlerStack(engineSrv, nil /* authCors */, cfg.AuthRpcVirtualHost, cfg.HttpCompression) - - engineApiHandler, err := createHandler(cfg, engineApi, engineHttpHandler, wsHandler, jwtSecret) - if err != nil { - return nil, nil, "", err - } - - engineListener, _, err := node.StartHTTPEndpoint(engineHttpEndpoint, cfg.AuthRpcTimeouts, engineApiHandler) - if err != nil { - return nil, nil, "", fmt.Errorf("could not start RPC api: %w", err) - } - - engineInfo := []interface{}{"url", engineHttpEndpoint, "ws", true, "ws.compression", cfg.WebsocketCompression} - log.Info("HTTP endpoint opened for Engine API", engineInfo...) - - return engineListener, engineSrv, engineHttpEndpoint, nil +// isWebsocket checks the header of a http request for a websocket upgrade request. +func isWebsocket(r *http.Request) bool { + return strings.EqualFold(r.Header.Get("Upgrade"), "websocket") && + strings.Contains(strings.ToLower(r.Header.Get("Connection")), "upgrade") } diff --git a/cmd/otter/cli/httpcfg/http_cfg.go b/cmd/otter/cli/httpcfg/http_cfg.go new file mode 100644 index 0000000..d8c67b9 --- /dev/null +++ b/cmd/otter/cli/httpcfg/http_cfg.go @@ -0,0 +1,18 @@ +package httpcfg + +import ( + "github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli/httpcfg" +) + +type HttpCfg struct { + httpcfg.HttpCfg + + DisableRpcDaemon bool + + OtsServerDisable bool + + OtsStaticDir string + OtsExternalAssetUrl string + OtsRpcDaemonUrl string + OtsBeaconApiUrl string +} diff --git a/cmd/rpcdaemon/cli/rpc_allow_list.go b/cmd/otter/cli/rpc_allow_list.go similarity index 100% rename from cmd/rpcdaemon/cli/rpc_allow_list.go rename to cmd/otter/cli/rpc_allow_list.go diff --git a/cmd/rpcdaemon/commands/daemon.go b/cmd/otter/commands/daemon.go similarity index 82% rename from cmd/rpcdaemon/commands/daemon.go rename to cmd/otter/commands/daemon.go index 090b420..0414aca 100644 --- a/cmd/rpcdaemon/commands/daemon.go +++ b/cmd/otter/commands/daemon.go @@ -10,7 +10,7 @@ import ( "github.com/ledgerwatch/erigon/turbo/rpchelper" "github.com/ledgerwatch/erigon/turbo/services" - "github.com/wmitsuda/otterscan/cmd/rpcdaemon/cli/httpcfg" + "github.com/wmitsuda/otterscan/cmd/otter/cli/httpcfg" erigonHttpcfg "github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli/httpcfg" ) @@ -130,27 +130,3 @@ func APIList(db kv.RoDB, borDb kv.RoDB, eth rpchelper.ApiBackend, txPool txpool. return list } - -func AuthAPIList(db kv.RoDB, eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, - filters *rpchelper.Filters, stateCache kvcache.Cache, blockReader services.FullBlockReader, - agg *libstate.Aggregator22, - cfg httpcfg.HttpCfg) (list []rpc.API) { - base := commands.NewBaseApi(filters, stateCache, blockReader, agg, cfg.WithDatadir, cfg.EvmCallTimeout) - - ethImpl := commands.NewEthAPI(base, db, eth, txPool, mining, cfg.Gascap) - engineImpl := commands.NewEngineAPI(base, db, eth) - - list = append(list, rpc.API{ - Namespace: "eth", - Public: true, - Service: commands.EthAPI(ethImpl), - Version: "1.0", - }, rpc.API{ - Namespace: "engine", - Public: true, - Service: commands.EngineAPI(engineImpl), - Version: "1.0", - }) - - return list -} diff --git a/cmd/rpcdaemon/commands/error_messages.go b/cmd/otter/commands/error_messages.go similarity index 100% rename from cmd/rpcdaemon/commands/error_messages.go rename to cmd/otter/commands/error_messages.go diff --git a/cmd/rpcdaemon/commands/get_chain_config_test.go b/cmd/otter/commands/get_chain_config_test.go similarity index 100% rename from cmd/rpcdaemon/commands/get_chain_config_test.go rename to cmd/otter/commands/get_chain_config_test.go diff --git a/cmd/rpcdaemon/commands/otterscan_api.go b/cmd/otter/commands/otterscan_api.go similarity index 99% rename from cmd/rpcdaemon/commands/otterscan_api.go rename to cmd/otter/commands/otterscan_api.go index 93e44cf..46db44b 100644 --- a/cmd/rpcdaemon/commands/otterscan_api.go +++ b/cmd/otter/commands/otterscan_api.go @@ -19,13 +19,11 @@ import ( "github.com/ledgerwatch/erigon/core/vm" "github.com/ledgerwatch/erigon/params" "github.com/ledgerwatch/erigon/rpc" + "github.com/ledgerwatch/erigon/turbo/adapter/ethapi" "github.com/ledgerwatch/erigon/turbo/rpchelper" "github.com/ledgerwatch/erigon/turbo/transactions" - "github.com/ledgerwatch/erigon/turbo/adapter/ethapi" - "github.com/ledgerwatch/log/v3" - ) // API_LEVEL Must be incremented every time new additions are made diff --git a/cmd/rpcdaemon/commands/otterscan_block_details.go b/cmd/otter/commands/otterscan_block_details.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_block_details.go rename to cmd/otter/commands/otterscan_block_details.go diff --git a/cmd/rpcdaemon/commands/otterscan_contract_creator.go b/cmd/otter/commands/otterscan_contract_creator.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_contract_creator.go rename to cmd/otter/commands/otterscan_contract_creator.go diff --git a/cmd/rpcdaemon/commands/otterscan_default_tracer.go b/cmd/otter/commands/otterscan_default_tracer.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_default_tracer.go rename to cmd/otter/commands/otterscan_default_tracer.go diff --git a/cmd/rpcdaemon/commands/otterscan_generic_tracer.go b/cmd/otter/commands/otterscan_generic_tracer.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_generic_tracer.go rename to cmd/otter/commands/otterscan_generic_tracer.go diff --git a/cmd/rpcdaemon/commands/otterscan_has_code.go b/cmd/otter/commands/otterscan_has_code.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_has_code.go rename to cmd/otter/commands/otterscan_has_code.go diff --git a/cmd/rpcdaemon/commands/otterscan_search_backward.go b/cmd/otter/commands/otterscan_search_backward.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_search_backward.go rename to cmd/otter/commands/otterscan_search_backward.go diff --git a/cmd/rpcdaemon/commands/otterscan_search_backward_multi_test.go b/cmd/otter/commands/otterscan_search_backward_multi_test.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_search_backward_multi_test.go rename to cmd/otter/commands/otterscan_search_backward_multi_test.go diff --git a/cmd/rpcdaemon/commands/otterscan_search_backward_test.go b/cmd/otter/commands/otterscan_search_backward_test.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_search_backward_test.go rename to cmd/otter/commands/otterscan_search_backward_test.go diff --git a/cmd/rpcdaemon/commands/otterscan_search_forward.go b/cmd/otter/commands/otterscan_search_forward.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_search_forward.go rename to cmd/otter/commands/otterscan_search_forward.go diff --git a/cmd/rpcdaemon/commands/otterscan_search_forward_multi_test.go b/cmd/otter/commands/otterscan_search_forward_multi_test.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_search_forward_multi_test.go rename to cmd/otter/commands/otterscan_search_forward_multi_test.go diff --git a/cmd/rpcdaemon/commands/otterscan_search_forward_test.go b/cmd/otter/commands/otterscan_search_forward_test.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_search_forward_test.go rename to cmd/otter/commands/otterscan_search_forward_test.go diff --git a/cmd/rpcdaemon/commands/otterscan_search_multi.go b/cmd/otter/commands/otterscan_search_multi.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_search_multi.go rename to cmd/otter/commands/otterscan_search_multi.go diff --git a/cmd/rpcdaemon/commands/otterscan_search_test.go b/cmd/otter/commands/otterscan_search_test.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_search_test.go rename to cmd/otter/commands/otterscan_search_test.go diff --git a/cmd/rpcdaemon/commands/otterscan_search_trace.go b/cmd/otter/commands/otterscan_search_trace.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_search_trace.go rename to cmd/otter/commands/otterscan_search_trace.go diff --git a/cmd/rpcdaemon/commands/otterscan_trace_contract_creator.go b/cmd/otter/commands/otterscan_trace_contract_creator.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_trace_contract_creator.go rename to cmd/otter/commands/otterscan_trace_contract_creator.go diff --git a/cmd/rpcdaemon/commands/otterscan_trace_operations.go b/cmd/otter/commands/otterscan_trace_operations.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_trace_operations.go rename to cmd/otter/commands/otterscan_trace_operations.go diff --git a/cmd/rpcdaemon/commands/otterscan_trace_touch.go b/cmd/otter/commands/otterscan_trace_touch.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_trace_touch.go rename to cmd/otter/commands/otterscan_trace_touch.go diff --git a/cmd/rpcdaemon/commands/otterscan_trace_transaction.go b/cmd/otter/commands/otterscan_trace_transaction.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_trace_transaction.go rename to cmd/otter/commands/otterscan_trace_transaction.go diff --git a/cmd/rpcdaemon/commands/otterscan_transaction_by_sender_and_nonce.go b/cmd/otter/commands/otterscan_transaction_by_sender_and_nonce.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_transaction_by_sender_and_nonce.go rename to cmd/otter/commands/otterscan_transaction_by_sender_and_nonce.go diff --git a/cmd/rpcdaemon/commands/otterscan_transaction_error.go b/cmd/otter/commands/otterscan_transaction_error.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_transaction_error.go rename to cmd/otter/commands/otterscan_transaction_error.go diff --git a/cmd/rpcdaemon/commands/otterscan_types.go b/cmd/otter/commands/otterscan_types.go similarity index 100% rename from cmd/rpcdaemon/commands/otterscan_types.go rename to cmd/otter/commands/otterscan_types.go diff --git a/cmd/rpcdaemon/commands/utils_eth_api.go b/cmd/otter/commands/utils_eth_api.go similarity index 100% rename from cmd/rpcdaemon/commands/utils_eth_api.go rename to cmd/otter/commands/utils_eth_api.go diff --git a/cmd/rpcdaemon/commands/utils_eth_call.go b/cmd/otter/commands/utils_eth_call.go similarity index 100% rename from cmd/rpcdaemon/commands/utils_eth_call.go rename to cmd/otter/commands/utils_eth_call.go diff --git a/cmd/rpcdaemon/commands/utils_eth_receipts.go b/cmd/otter/commands/utils_eth_receipts.go similarity index 100% rename from cmd/rpcdaemon/commands/utils_eth_receipts.go rename to cmd/otter/commands/utils_eth_receipts.go diff --git a/cmd/rpcdaemon/commands/utils_storage_range.go b/cmd/otter/commands/utils_storage_range.go similarity index 100% rename from cmd/rpcdaemon/commands/utils_storage_range.go rename to cmd/otter/commands/utils_storage_range.go diff --git a/cmd/rpcdaemon/health/check_block.go b/cmd/otter/health/check_block.go similarity index 100% rename from cmd/rpcdaemon/health/check_block.go rename to cmd/otter/health/check_block.go diff --git a/cmd/rpcdaemon/health/check_peers.go b/cmd/otter/health/check_peers.go similarity index 100% rename from cmd/rpcdaemon/health/check_peers.go rename to cmd/otter/health/check_peers.go diff --git a/cmd/rpcdaemon/health/check_synced.go b/cmd/otter/health/check_synced.go similarity index 100% rename from cmd/rpcdaemon/health/check_synced.go rename to cmd/otter/health/check_synced.go diff --git a/cmd/rpcdaemon/health/check_time.go b/cmd/otter/health/check_time.go similarity index 100% rename from cmd/rpcdaemon/health/check_time.go rename to cmd/otter/health/check_time.go diff --git a/cmd/rpcdaemon/health/health.go b/cmd/otter/health/health.go similarity index 100% rename from cmd/rpcdaemon/health/health.go rename to cmd/otter/health/health.go diff --git a/cmd/rpcdaemon/health/health_test.go b/cmd/otter/health/health_test.go similarity index 100% rename from cmd/rpcdaemon/health/health_test.go rename to cmd/otter/health/health_test.go diff --git a/cmd/rpcdaemon/health/interfaces.go b/cmd/otter/health/interfaces.go similarity index 100% rename from cmd/rpcdaemon/health/interfaces.go rename to cmd/otter/health/interfaces.go diff --git a/cmd/rpcdaemon/health/parse_api.go b/cmd/otter/health/parse_api.go similarity index 100% rename from cmd/rpcdaemon/health/parse_api.go rename to cmd/otter/health/parse_api.go diff --git a/cmd/rpcdaemon/main.go b/cmd/otter/main.go similarity index 77% rename from cmd/rpcdaemon/main.go rename to cmd/otter/main.go index 0510168..a030a4f 100644 --- a/cmd/rpcdaemon/main.go +++ b/cmd/otter/main.go @@ -3,12 +3,13 @@ package main import ( "os" + "github.com/go-chi/chi/v5" "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/log/v3" "github.com/spf13/cobra" - "github.com/wmitsuda/otterscan/cmd/rpcdaemon/cli" - mycmds "github.com/wmitsuda/otterscan/cmd/rpcdaemon/commands" + "github.com/wmitsuda/otterscan/cmd/otter/cli" + mycmds "github.com/wmitsuda/otterscan/cmd/otter/commands" ) func main() { @@ -26,16 +27,15 @@ func main() { if borDb != nil { defer borDb.Close() } - + r := chi.NewRouter() + RouteServer(r, *cfg) apiList := mycmds.APIList(db, borDb, backend, txPool, mining, ff, stateCache, blockReader, agg, *cfg) - if err := cli.StartRpcServer(ctx, *cfg, apiList, nil); err != nil { + if err := cli.StartRpcServer(ctx, r, *cfg, apiList); err != nil { log.Error(err.Error()) return nil } - return nil } - if err := cmd.ExecuteContext(rootCtx); err != nil { log.Error(err.Error()) os.Exit(1) diff --git a/cmd/rpcdaemon/postman/README.md b/cmd/otter/postman/README.md similarity index 100% rename from cmd/rpcdaemon/postman/README.md rename to cmd/otter/postman/README.md diff --git a/cmd/rpcdaemon/postman/RPC_Testing.json b/cmd/otter/postman/RPC_Testing.json similarity index 100% rename from cmd/rpcdaemon/postman/RPC_Testing.json rename to cmd/otter/postman/RPC_Testing.json diff --git a/cmd/rpcdaemon/postman/Trace_Testing.json b/cmd/otter/postman/Trace_Testing.json similarity index 100% rename from cmd/rpcdaemon/postman/Trace_Testing.json rename to cmd/otter/postman/Trace_Testing.json diff --git a/cmd/rpcdaemon/rpcdaemontest/test_util.go b/cmd/otter/rpcdaemontest/test_util.go similarity index 100% rename from cmd/rpcdaemon/rpcdaemontest/test_util.go rename to cmd/otter/rpcdaemontest/test_util.go diff --git a/cmd/rpcdaemon/rpcservices/eth_backend.go b/cmd/otter/rpcservices/eth_backend.go similarity index 100% rename from cmd/rpcdaemon/rpcservices/eth_backend.go rename to cmd/otter/rpcservices/eth_backend.go diff --git a/cmd/rpcdaemon/rpcservices/eth_mining.go b/cmd/otter/rpcservices/eth_mining.go similarity index 100% rename from cmd/rpcdaemon/rpcservices/eth_mining.go rename to cmd/otter/rpcservices/eth_mining.go diff --git a/cmd/rpcdaemon/rpcservices/eth_txpool.go b/cmd/otter/rpcservices/eth_txpool.go similarity index 100% rename from cmd/rpcdaemon/rpcservices/eth_txpool.go rename to cmd/otter/rpcservices/eth_txpool.go diff --git a/cmd/otter/server.go b/cmd/otter/server.go new file mode 100644 index 0000000..f80c995 --- /dev/null +++ b/cmd/otter/server.go @@ -0,0 +1,48 @@ +package main + +import ( + "encoding/json" + "net/http" + "strings" + + "gfx.cafe/open/4bytes/sigs" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + "github.com/wmitsuda/otterscan/cmd/otter/cli/httpcfg" +) + +func RouteServer(r chi.Router, cfg httpcfg.HttpCfg) { + r.Group(func(r chi.Router) { + filesDir := http.Dir(cfg.OtsStaticDir) + r.Use(middleware.Logger) + r.Use(middleware.Recoverer) + r.Handle("/signatures/{hash}", &sigs.HttpServer{}) + r.HandleFunc("/config.json", func(w http.ResponseWriter, r *http.Request) { + json.NewEncoder(w).Encode(map[string]any{ + "erigonURL": cfg.OtsRpcDaemonUrl, + "beaconAPI": cfg.OtsBeaconApiUrl, + "assetsURLPrefix": cfg.OtsBeaconApiUrl, + }) + }) + FileServer(r, "/", filesDir) + }) +} + +// FileServer conveniently sets up a http.FileServer handler to serve +// static files from a http.FileSystem. +func FileServer(r chi.Router, path string, root http.FileSystem) { + if strings.ContainsAny(path, "{}*") { + panic("FileServer does not permit any URL parameters.") + } + if path != "/" && path[len(path)-1] != '/' { + r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP) + path += "/" + } + path += "*" + r.Get(path, func(w http.ResponseWriter, r *http.Request) { + rctx := chi.RouteContext(r.Context()) + pathPrefix := strings.TrimSuffix(rctx.RoutePattern(), "/*") + fs := http.StripPrefix(pathPrefix, http.FileServer(root)) + fs.ServeHTTP(w, r) + }) +} diff --git a/cmd/rpcdaemon/test.http b/cmd/otter/test.http similarity index 100% rename from cmd/rpcdaemon/test.http rename to cmd/otter/test.http diff --git a/cmd/rpcdaemon/testdata/.gitignore b/cmd/otter/testdata/.gitignore similarity index 100% rename from cmd/rpcdaemon/testdata/.gitignore rename to cmd/otter/testdata/.gitignore diff --git a/cmd/rpcdaemon/testdata/sed_file b/cmd/otter/testdata/sed_file similarity index 100% rename from cmd/rpcdaemon/testdata/sed_file rename to cmd/otter/testdata/sed_file diff --git a/cmd/rpcdaemon/testdata/trace_tests b/cmd/otter/testdata/trace_tests similarity index 100% rename from cmd/rpcdaemon/testdata/trace_tests rename to cmd/otter/testdata/trace_tests diff --git a/cmd/rpcdaemon/cli/httpcfg/http_cfg.go b/cmd/rpcdaemon/cli/httpcfg/http_cfg.go deleted file mode 100644 index 6d490d8..0000000 --- a/cmd/rpcdaemon/cli/httpcfg/http_cfg.go +++ /dev/null @@ -1,52 +0,0 @@ -package httpcfg - -import ( - "github.com/ledgerwatch/erigon-lib/kv/kvcache" - "github.com/ledgerwatch/erigon/eth/ethconfig" - "github.com/ledgerwatch/erigon/node/nodecfg/datadir" - "github.com/ledgerwatch/erigon/rpc/rpccfg" - "time" -) - -type HttpCfg struct { - Enabled bool - PrivateApiAddr string - WithDatadir bool // Erigon's database can be read by separated processes on same machine - in read-only mode - with full support of transactions. It will share same "OS PageCache" with Erigon process. - DataDir string - Dirs datadir.Dirs - HttpListenAddress string - AuthRpcHTTPListenAddress string - TLSCertfile string - TLSCACert string - TLSKeyFile string - HttpPort int - AuthRpcPort int - HttpCORSDomain []string - HttpVirtualHost []string - AuthRpcVirtualHost []string - HttpCompression bool - API []string - Gascap uint64 - MaxTraces uint64 - WebsocketEnabled bool - WebsocketCompression bool - RpcAllowListFilePath string - RpcBatchConcurrency uint - RpcStreamingDisable bool - DBReadConcurrency int - TraceCompatibility bool // Bug for bug compatibility for trace_ routines with OpenEthereum - TxPoolApiAddr string - StateCache kvcache.CoherentConfig - Snap ethconfig.Snapshot - Sync ethconfig.Sync - GRPCServerEnabled bool - GRPCListenAddress string - GRPCPort int - GRPCHealthCheckEnabled bool - StarknetGRPCAddress string - JWTSecretPath string // Engine API Authentication - TraceRequests bool // Always trace requests in INFO level - HTTPTimeouts rpccfg.HTTPTimeouts - AuthRpcTimeouts rpccfg.HTTPTimeouts - EvmCallTimeout time.Duration -} diff --git a/cmd/server/main.go b/cmd/server/main.go deleted file mode 100644 index 3957e24..0000000 --- a/cmd/server/main.go +++ /dev/null @@ -1,72 +0,0 @@ -package main - -import ( - "log" - "net/http" - "os" - "strings" - "time" - - "gfx.cafe/open/4bytes/sigs" - "github.com/go-chi/chi/v5" - "github.com/go-chi/chi/v5/middleware" -) - -func main() { - root := "dist" - port := os.Getenv("PORT") - if port == "" { - port = "3001" - } - if os.Getenv("ROOTDIR") != "" { - root = os.Getenv("ROOTDIR") - } - if len(os.Args) > 1 { - if os.Args[1] != "" { - root = os.Args[1] - } - } - filesDir := http.Dir(root) - - r := chi.NewRouter() - r.Use(middleware.Logger) - r.Use(middleware.Recoverer) - r.Use(middleware.SetHeader("Access-Control-Allow-Origin", "*")) - - r.Handle("/signatures/{hash}", &sigs.HttpServer{}) - - FileServer(r, "/", filesDir) - - s := http.Server{ - Addr: ":" + port, - Handler: r, - } - s.SetKeepAlivesEnabled(false) - s.ReadHeaderTimeout = 250 * time.Millisecond - s.MaxHeaderBytes = 8192 - - log.Println("static asset server running on " + port) - // Start the server. - if err := s.ListenAndServe(); err != nil { - log.Fatalf("error in ListenAndServe: %v", err) - } -} - -// FileServer conveniently sets up a http.FileServer handler to serve -// static files from a http.FileSystem. -func FileServer(r chi.Router, path string, root http.FileSystem) { - if strings.ContainsAny(path, "{}*") { - panic("FileServer does not permit any URL parameters.") - } - if path != "/" && path[len(path)-1] != '/' { - r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP) - path += "/" - } - path += "*" - r.Get(path, func(w http.ResponseWriter, r *http.Request) { - rctx := chi.RouteContext(r.Context()) - pathPrefix := strings.TrimSuffix(rctx.RoutePattern(), "/*") - fs := http.StripPrefix(pathPrefix, http.FileServer(root)) - fs.ServeHTTP(w, r) - }) -} diff --git a/docker-compose.yaml b/docker-compose.yaml index 6c63b8e..44dbda2 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -2,11 +2,11 @@ version: '3.9' services: - rpcdaemon: + otterscan: build: context: . command: | - rpcdaemon + otter --http.addr=0.0.0.0 --http.vhosts=* --http.corsdomain=* --ws --http.api=eth,erigon,web3,net,trace,debug,txpool,ots --metrics --metrics.addr=0.0.0.0 --metrics.port=6064 @@ -14,11 +14,4 @@ services: --private.api.addr=172.105.22.234:9191 ##--datadir=/erigon ports: - - 8545:8545 - server: - build: - context: . - command: | - server - ports: - - 3001:3001 + - 3000:8545 diff --git a/public/config.json b/public/config.json deleted file mode 100644 index 40b1cb8..0000000 --- a/public/config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "erigonURL": "http://localhost:8545", - "beaconAPI": "http://localhost:3500", - "assetsURLPrefix": "/" -}