Skip to content
Merged
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
28 changes: 12 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,29 +174,25 @@ Windows users may run erigon in 3 possible ways:
**Please also note the default WSL2 environment has its own IP address which does not match the one of the network
interface of Windows host: take this into account when configuring NAT for port 30303 on your router.**

### Beacon Chain
### Beacon Chain (Consensus Layer)

Erigon can be used as an execution-layer for beacon chain consensus clients (Eth2). Default configuration is ok. Eth2
relies on availability of receipts - don't prune them: don't add character `r` to `--prune` flag. However, old receipts
are not needed for Eth2 and you can safely prune them with `--prune.r.before=11184524` in combination with `--prune htc`.
Erigon can be used as an Execution Layer (EL) for Consensus Layer clients (CL). Default configuration is OK. CL
relies on availability of receipts don't prune them: don't add character `r` to `--prune` flag. However, old receipts
are not needed for CL and you can safely prune them with `--prune.r.before=<old block number>` in combination with `--prune htc`.

You must enable JSON-RPC by `--http` and add `engine` to `--http.api` list. (Or run the [JSON-RPC daemon](#json-rpc-daemon) in addition to the Erigon)
If your CL client is on a different device, add `--authrpc.addr 0.0.0.0` ([Engine API] listens on localhost by default)
as well as `--authrpc.vhosts <CL host>`.

If beacon chain client on a different device: add `--http.addr 0.0.0.0` (JSON-RPC listen on localhost by default)
.

Once the JSON-RPC is running, all you need to do is point your beacon chain client to `<ip address>:8545`,
where `<ip address>` is either localhost or the IP address of the device running the JSON-RPC.

Erigon has been tested with Lighthouse however all other clients that support JSON-RPC should also work.

### Authentication API
[Engine API]: https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md

In order to establish a secure connection between the Consensus Layer and the Execution Layer, a JWT secret key is automatically generated.

The JWT secret key will be present in the datadir by default under the name of `jwt.hex` and its path can be specified with the flag `--authrpc.jwtsecret`.

This piece of info needs to be specified in the Consensus Layer as well in order to establish connection successfully. More information can be found [here](https://github.com/ethereum/execution-apis/blob/main/src/engine/authentication.md)
This piece of info needs to be specified in the Consensus Layer as well in order to establish connection successfully. More information can be found [here](https://github.com/ethereum/execution-apis/blob/main/src/engine/authentication.md).

Once Erigon is running, you need to point your CL client to `<erigon address>:8551`,
where `<erigon address>` is either `localhost` or the IP address of the device running Erigon, and also point to the JWT secret path created by Erigon.

### Multiple Instances / One Machine

Expand Down Expand Up @@ -426,7 +422,7 @@ internally for rpcdaemon or other connections, (e.g. rpcdaemon -> erigon).
| 8551 | TCP | HTTP with JWT auth | Private |

Typically, 8545 is exposed only internally for JSON-RPC queries. Both HTTP and WebSocket connections are on the same port.
Typically, 8551 (JWT authenticated) is exposed only internally for the Engine API JSON-RPC queries.
Typically, 8551 (JWT authenticated) is exposed only internally for the [Engine API] JSON-RPC queries.

#### `sentry` ports

Expand Down
70 changes: 13 additions & 57 deletions cmd/rpcdaemon/cli/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,15 @@ func RootCommand() (*cobra.Command, *httpcfg.HttpCfg) {
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")
rootCmd.PersistentFlags().StringVar(&cfg.EngineHTTPListenAddress, "engine.addr", nodecfg.DefaultHTTPHost, "HTTP-RPC server listening interface for engineAPI")
rootCmd.PersistentFlags().StringVar(&cfg.AuthRpcHTTPListenAddress, "authrpc.addr", nodecfg.DefaultHTTPHost, "HTTP-RPC server listening interface for the Engine API")
rootCmd.PersistentFlags().StringVar(&cfg.TLSCertfile, "tls.cert", "", "certificate for client side TLS handshake")
rootCmd.PersistentFlags().StringVar(&cfg.TLSKeyFile, "tls.key", "", "key file for client side TLS handshake")
rootCmd.PersistentFlags().StringVar(&cfg.TLSCACert, "tls.cacert", "", "CA certificate for client side TLS handshake")
rootCmd.PersistentFlags().IntVar(&cfg.HttpPort, "http.port", nodecfg.DefaultHTTPPort, "HTTP-RPC server listening port")
rootCmd.PersistentFlags().IntVar(&cfg.EnginePort, "engine.port", nodecfg.DefaultEngineHTTPPort, "HTTP-RPC server listening port for the engineAPI")
rootCmd.PersistentFlags().IntVar(&cfg.AuthRpcPort, "authrpc.port", nodecfg.DefaultAuthRpcPort, "HTTP-RPC server listening port for the Engine API")
rootCmd.PersistentFlags().StringSliceVar(&cfg.HttpCORSDomain, "http.corsdomain", []string{}, "Comma separated list of domains from which to accept cross origin requests (browser enforced)")
rootCmd.PersistentFlags().StringSliceVar(&cfg.HttpVirtualHost, "http.vhosts", nodecfg.DefaultConfig.HTTPVirtualHosts, "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.")
rootCmd.PersistentFlags().StringSliceVar(&cfg.AuthRpcVirtualHost, "authrpc.vhosts", nodecfg.DefaultConfig.HTTPVirtualHosts, "Comma separated list of virtual hostnames from which to accept Engine API requests (server enforced). Accepts '*' wildcard.")
rootCmd.PersistentFlags().BoolVar(&cfg.HttpCompression, "http.compression", true, "Disable http compression")
rootCmd.PersistentFlags().StringSliceVar(&cfg.API, "http.api", []string{"eth", "erigon"}, "API's offered over the HTTP-RPC interface: eth,erigon,web3,net,debug,trace,txpool,db,starknet. Supported methods: https://github.com/ledgerwatch/erigon/tree/devel/cmd/rpcdaemon")
rootCmd.PersistentFlags().Uint64Var(&cfg.Gascap, "rpc.gascap", 50000000, "Sets a cap on gas that can be used in eth_call/estimateGas")
Expand All @@ -99,9 +100,9 @@ func RootCommand() (*cobra.Command, *httpcfg.HttpCfg) {
rootCmd.PersistentFlags().DurationVar(&cfg.HTTPTimeouts.ReadTimeout, "http.timeouts.read", rpccfg.DefaultHTTPTimeouts.ReadTimeout, "Maximum duration for reading the entire request, including the body.")
rootCmd.PersistentFlags().DurationVar(&cfg.HTTPTimeouts.WriteTimeout, "http.timeouts.write", rpccfg.DefaultHTTPTimeouts.WriteTimeout, "Maximum duration before timing out writes of the response. It is reset whenever a new request's header is read")
rootCmd.PersistentFlags().DurationVar(&cfg.HTTPTimeouts.IdleTimeout, "http.timeouts.idle", rpccfg.DefaultHTTPTimeouts.IdleTimeout, "Maximum amount of time to wait for the next request when keep-alives are enabled. If http.timeouts.idle is zero, the value of http.timeouts.read is used")
rootCmd.PersistentFlags().DurationVar(&cfg.EngineTimeouts.ReadTimeout, "engine.timeouts.read", rpccfg.DefaultHTTPTimeouts.ReadTimeout, "Maximum duration for reading the entire request, including the body.")
rootCmd.PersistentFlags().DurationVar(&cfg.EngineTimeouts.WriteTimeout, "engine.timeouts.write", rpccfg.DefaultHTTPTimeouts.WriteTimeout, "Maximum duration before timing out writes of the response. It is reset whenever a new request's header is read.")
rootCmd.PersistentFlags().DurationVar(&cfg.EngineTimeouts.IdleTimeout, "engine.timeouts.idle", rpccfg.DefaultHTTPTimeouts.IdleTimeout, "Maximum amount of time to wait for the next request when keep-alives are enabled. If engine.timeouts.idle is zero, the value of engine.timeouts.read is used.")
rootCmd.PersistentFlags().DurationVar(&cfg.AuthRpcTimeouts.ReadTimeout, "authrpc.timeouts.read", rpccfg.DefaultHTTPTimeouts.ReadTimeout, "Maximum duration for reading the entire request, including the body.")
rootCmd.PersistentFlags().DurationVar(&cfg.AuthRpcTimeouts.WriteTimeout, "authrpc.timeouts.write", rpccfg.DefaultHTTPTimeouts.WriteTimeout, "Maximum duration before timing out writes of the response. It is reset whenever a new request's header is read.")
rootCmd.PersistentFlags().DurationVar(&cfg.AuthRpcTimeouts.IdleTimeout, "authrpc.timeouts.idle", rpccfg.DefaultHTTPTimeouts.IdleTimeout, "Maximum amount of time to wait for the next request when keep-alives are enabled. If authrpc.timeouts.idle is zero, the value of authrpc.timeouts.read is used.")

if err := rootCmd.MarkPersistentFlagFilename("rpc.accessList", "json"); err != nil {
panic(err)
Expand Down Expand Up @@ -320,29 +321,6 @@ func RemoteServices(ctx context.Context, cfg httpcfg.HttpCfg, logger log.Logger,
return nil, nil, nil, nil, nil, nil, nil, nil, ff, fmt.Errorf("chain config not found in db. Need start erigon at least once on this db")
}
cfg.Snap.Enabled = cfg.Snap.Enabled || cfg.Sync.UseSnapshots

// if chain config has terminal total difficulty then rpc must have eth and engine APIs enableds
if cc.TerminalTotalDifficulty != nil {
hasEthApiEnabled := false
hasEngineApiEnabled := false

for _, api := range cfg.API {
switch api {
case "eth":
hasEthApiEnabled = true
case "engine":
hasEngineApiEnabled = true
}
}

if !hasEthApiEnabled {
cfg.API = append(cfg.API, "eth")
}

if !hasEngineApiEnabled {
cfg.API = append(cfg.API, "engine")
}
}
}

creds, err := grpcutil.TLS(cfg.TLSCACert, cfg.TLSCertfile, cfg.TLSKeyFile)
Expand Down Expand Up @@ -554,25 +532,12 @@ type engineInfo struct {
}

func startAuthenticatedRpcServer(cfg httpcfg.HttpCfg, rpcAPI []rpc.API) (*engineInfo, error) {
var engineListener *http.Server
var engineSrv *rpc.Server
var engineHttpEndpoint string
var err error

log.Trace("TraceRequests = %t\n", cfg.TraceRequests)
srv := rpc.NewServer(cfg.RpcBatchConcurrency, cfg.TraceRequests, cfg.RpcStreamingDisable)

var rpcAPIList []rpc.API

for _, api := range rpcAPI {
rpcAPIList = append(rpcAPIList, api)
}

if len(rpcAPIList) > 0 {
engineListener, engineSrv, engineHttpEndpoint, err = createEngineListener(cfg, rpcAPIList)
if err != nil {
return nil, fmt.Errorf("could not start RPC api for engine: %w", err)
}
engineListener, engineSrv, engineHttpEndpoint, err := createEngineListener(cfg, rpcAPI)
if err != nil {
return nil, fmt.Errorf("could not start RPC api for engine: %w", err)
}
return &engineInfo{Srv: srv, EngineSrv: engineSrv, EngineListener: engineListener, EngineHttpEndpoint: engineHttpEndpoint}, nil
}
Expand Down Expand Up @@ -652,16 +617,10 @@ func createHandler(cfg httpcfg.HttpCfg, apiList []rpc.API, httpHandler http.Hand
}

func createEngineListener(cfg httpcfg.HttpCfg, engineApi []rpc.API) (*http.Server, *rpc.Server, string, error) {
engineHttpEndpoint := fmt.Sprintf("%s:%d", cfg.EngineHTTPListenAddress, cfg.EnginePort)
engineHttpEndpoint := fmt.Sprintf("%s:%d", cfg.AuthRpcHTTPListenAddress, cfg.AuthRpcPort)

engineSrv := rpc.NewServer(cfg.RpcBatchConcurrency, cfg.TraceRequests, true)

allowListForRPC, err := parseAllowListForRPC(cfg.RpcAllowListFilePath)
if err != nil {
return nil, nil, "", err
}
engineSrv.SetAllowList(allowListForRPC)

if err := node.RegisterApisFromWhitelist(engineApi, nil, engineSrv, true); err != nil {
return nil, nil, "", fmt.Errorf("could not start register RPC engine api: %w", err)
}
Expand All @@ -671,19 +630,16 @@ func createEngineListener(cfg httpcfg.HttpCfg, engineApi []rpc.API) (*http.Serve
return nil, nil, "", err
}

var wsHandler http.Handler
if cfg.WebsocketEnabled {
wsHandler = engineSrv.WebsocketHandler([]string{"*"}, jwtSecret, cfg.WebsocketCompression)
}
wsHandler := engineSrv.WebsocketHandler([]string{"*"}, jwtSecret, cfg.WebsocketCompression)

engineHttpHandler := node.NewHTTPHandlerStack(engineSrv, cfg.HttpCORSDomain, cfg.HttpVirtualHost, cfg.HttpCompression)
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.EngineTimeouts, engineApiHandler)
engineListener, _, err := node.StartHTTPEndpoint(engineHttpEndpoint, cfg.AuthRpcTimeouts, engineApiHandler)
if err != nil {
return nil, nil, "", fmt.Errorf("could not start RPC api: %w", err)
}
Expand Down
79 changes: 40 additions & 39 deletions cmd/rpcdaemon/cli/httpcfg/http_cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,44 @@ import (
)

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
EngineHTTPListenAddress string
TLSCertfile string
TLSCACert string
TLSKeyFile string
HttpPort int
EnginePort int
HttpCORSDomain []string
HttpVirtualHost []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
TevmEnabled bool
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
EngineTimeouts rpccfg.HTTPTimeouts
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
TevmEnabled bool
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
}
4 changes: 2 additions & 2 deletions cmd/rpcdaemon22/cli/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ func RootCommand() (*cobra.Command, *httpcfg.HttpCfg) {
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")
rootCmd.PersistentFlags().StringVar(&cfg.EngineHTTPListenAddress, "engine.addr", nodecfg.DefaultHTTPHost, "HTTP-RPC server listening interface for engineAPI")
rootCmd.PersistentFlags().StringVar(&cfg.EngineHTTPListenAddress, "authrpc.addr", nodecfg.DefaultHTTPHost, "HTTP-RPC server listening interface for engineAPI")
rootCmd.PersistentFlags().StringVar(&cfg.TLSCertfile, "tls.cert", "", "certificate for client side TLS handshake")
rootCmd.PersistentFlags().StringVar(&cfg.TLSKeyFile, "tls.key", "", "key file for client side TLS handshake")
rootCmd.PersistentFlags().StringVar(&cfg.TLSCACert, "tls.cacert", "", "CA certificate for client side TLS handshake")
rootCmd.PersistentFlags().IntVar(&cfg.HttpPort, "http.port", nodecfg.DefaultHTTPPort, "HTTP-RPC server listening port")
rootCmd.PersistentFlags().IntVar(&cfg.EnginePort, "engine.port", nodecfg.DefaultEngineHTTPPort, "HTTP-RPC server listening port for the engineAPI")
rootCmd.PersistentFlags().IntVar(&cfg.EnginePort, "authrpc.port", nodecfg.DefaultAuthRpcPort, "HTTP-RPC server listening port for the engineAPI")
rootCmd.PersistentFlags().StringSliceVar(&cfg.HttpCORSDomain, "http.corsdomain", []string{}, "Comma separated list of domains from which to accept cross origin requests (browser enforced)")
rootCmd.PersistentFlags().StringSliceVar(&cfg.HttpVirtualHost, "http.vhosts", nodecfg.DefaultConfig.HTTPVirtualHosts, "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.")
rootCmd.PersistentFlags().BoolVar(&cfg.HttpCompression, "http.compression", true, "Disable http compression")
Expand Down
19 changes: 12 additions & 7 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,15 +322,15 @@ var (
Usage: "HTTP-RPC server listening port",
Value: nodecfg.DefaultHTTPPort,
}
EngineAddr = cli.StringFlag{
Name: "engine.addr",
Usage: "HTTP-RPC server listening interface for engineAPI",
AuthRpcAddr = cli.StringFlag{
Name: "authrpc.addr",
Usage: "HTTP-RPC server listening interface for the Engine API",
Value: nodecfg.DefaultHTTPHost,
}
EnginePort = cli.UintFlag{
Name: "engine.port",
Usage: "HTTP-RPC server listening port for the engineAPI",
Value: nodecfg.DefaultEngineHTTPPort,
AuthRpcPort = cli.UintFlag{
Name: "authrpc.port",
Usage: "HTTP-RPC server listening port for the Engine API",
Value: nodecfg.DefaultAuthRpcPort,
}

JWTSecretPath = cli.StringFlag{
Expand All @@ -357,6 +357,11 @@ var (
Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
Value: strings.Join(nodecfg.DefaultConfig.HTTPVirtualHosts, ","),
}
AuthRpcVirtualHostsFlag = cli.StringFlag{
Name: "authrpc.vhosts",
Usage: "Comma separated list of virtual hostnames from which to accept Engine API requests (server enforced). Accepts '*' wildcard.",
Value: strings.Join(nodecfg.DefaultConfig.HTTPVirtualHosts, ","),
}
HTTPApiFlag = cli.StringFlag{
Name: "http.api",
Usage: "API's offered over the HTTP-RPC interface",
Expand Down
Loading