Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Nimbus beacon node is an Ethereum consensus layer client. Should be deployed together with an execution layer client like Geth. Signed-off-by: Jakub Sokołowski <jakub@status.im>
- Loading branch information
Showing
6 changed files
with
408 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Nimbus Beacon Node {#module-services-nimbus-beacon-node} | ||
|
||
# Quick Start {#module-services-nimbus-beacon-node-quick-start} | ||
Nimbus is an extremely efficient consensus layer client implementation. | ||
While it's optimised for embedded systems and resource-restricted devices -- | ||
including Raspberry Pis, its low resource usage also makes it an excellent choice | ||
for any server or desktop (where it simply takes up fewer resources). | ||
|
||
In order for the [Consensus Layer(CL) client](https://ethereum.org/en/developers/docs/nodes-and-clients/#consensus-clients) | ||
to function it requires access to an [Execution Layer(EL) client](https://ethereum.org/en/developers/docs/nodes-and-clients/#execution-clients) | ||
listening for AuthRPC requests on `http://localhost:8551/`. | ||
An example configuration using Geth as the EL client would look like this: | ||
|
||
```nix | ||
# Execution layer client | ||
services.geth.mainnet = { | ||
enable = true; | ||
authrpc = { | ||
enable = true; | ||
port = 8551; | ||
vhosts = ["localhost"]; | ||
jwtsecret = "/var/run/geth/jwtsecret"; | ||
}; | ||
}; | ||
# Consensus layer client | ||
services.nimbus-beacon-node = { | ||
enable = true; | ||
web3Urls = ["http://localhost:${toString config.services.geth.mainnet.authrpc.port}"]; | ||
jwtSecret = "/var/run/geth/jwtsecret"; | ||
rest.enable = true; | ||
}; | ||
``` | ||
::: {.warning} | ||
This assumes you have a `/var/run/geth/jwtsecret` containing a 64 byte secret. | ||
You can create such a secret using `openssl rand -hex 32 | tr -d "\n"`. | ||
::: | ||
|
||
This should allow the CL node to communicate with EL node via Auth RPC. | ||
|
||
Keep in mind that the JWT secret needs to be the same and readable for both nodes. | ||
If both services run on the same host and listen on `localhost` it's just a formality. | ||
|
||
You can check if the node is working using the REST API: | ||
|
||
{command}`curl -s localhost:5052/eth/v1/node/version` | ||
```json | ||
{"data":{"version":"Nimbus/v22.9.1-ad286b-stateofus"}} | ||
``` | ||
{command}`curl -s localhost:5052/eth/v1/node/syncing` | ||
```json | ||
{"data":{"head_slot":"45102","sync_distance":"4744542","is_syncing":true,"is_optimistic":false}} | ||
``` | ||
|
||
# Configuration {#module-services-nimbus-beacon-node-configuration} | ||
|
||
Other settings worth looking at include: | ||
|
||
* {option}`services.nimbus-beacon-node.suggestedFeeRecipient` - Your address for receiving [transaction fees](https://nimbus.guide/suggested-fee-recipient.html). | ||
* {option}`services.nimbus-beacon-node.doppelganger` - Miss two epochs to avoid [validator slashing](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/rewards-and-penalties/#slashing). | ||
* {option}`services.nimbus-beacon-node.metrics.enable` - Prometheus metrics endpoint listening on `9100` by default. | ||
* {option}`services.nimbus-beacon-node.extraArgs` - Ability to provide flags not defined in the service. | ||
|
||
For documentation see: <https://nimbus.guide/> |
236 changes: 236 additions & 0 deletions
236
nixos/modules/services/blockchain/nimbus/beacon-node.nix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
{ config, lib, pkgs, ... }: | ||
|
||
let | ||
inherit (lib) | ||
escapeShellArg mdDoc literalMD concatStringsSep mkMerge | ||
toUpper boolToString length forEach optionals optionalAttrs | ||
types mkEnableOption mkOption mkIf literalExpression; | ||
|
||
cfg = config.services.nimbus-beacon-node; | ||
in { | ||
options = { | ||
services = { | ||
nimbus-beacon-node = { | ||
enable = mkEnableOption (mdDoc "Nimbus Beacon Node service"); | ||
|
||
package = mkOption { | ||
type = types.package; | ||
default = pkgs.nimbus; | ||
defaultText = literalExpression "pkgs.nimbus"; | ||
description = mdDoc "Package to use as Go Ethereum node."; | ||
}; | ||
|
||
service = { | ||
user = mkOption { | ||
type = types.str; | ||
default = "nimbus"; | ||
description = mdDoc "Username for Nimbus beacon node service."; | ||
}; | ||
|
||
group = mkOption { | ||
type = types.str; | ||
default = "nimbus"; | ||
description = mdDoc "Group name for Nimbus beacon node service."; | ||
}; | ||
}; | ||
|
||
dataDir = mkOption { | ||
type = types.path; | ||
default = "/var/lib/nimbus-beacon-node"; | ||
description = mdDoc "Directory for Nimbus beacon node blockchain data."; | ||
}; | ||
|
||
network = mkOption { | ||
type = types.str; | ||
default = "mainnet"; | ||
description = mdDoc "Name of beacon node network to connect to."; | ||
}; | ||
|
||
log = { | ||
level = mkOption { | ||
type = types.enum ["trace" "debug" "info" "notice" "warn" "error" "fatal" "none"]; | ||
default = "info"; | ||
example = "debug"; | ||
description = mdDoc "Logging level."; | ||
}; | ||
|
||
format = mkOption { | ||
type = types.enum ["auto" "colors" "nocolors" "json"]; | ||
default = "auto"; | ||
example = "json"; | ||
description = mdDoc "Logging formatting."; | ||
}; | ||
}; | ||
|
||
web3Urls = mkOption { | ||
type = types.listOf types.str; | ||
default = []; | ||
example = ["http://localhost:8551/"]; | ||
description = mdDoc "Mandatory URL(s) for the Web3 RPC endpoints."; | ||
}; | ||
|
||
jwtSecret = mkOption { | ||
type = types.path; | ||
default = null; | ||
example = "/var/run/nimbus/jwtsecret"; | ||
description = mdDoc '' | ||
Path of file with 32 bytes long JWT secret for Auth RPC endpoint. | ||
Can be generated using 'openssl rand -hex 32'. | ||
''; | ||
}; | ||
|
||
subAllSubnets = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = mdDoc "Subscribe to all attestation subnet topics."; | ||
}; | ||
|
||
doppelganger = mkOption { | ||
type = types.bool; | ||
default = true; | ||
description = mdDoc '' | ||
Protection against slashing due to double-voting. | ||
Means you will miss two attestations when restarting. | ||
''; | ||
}; | ||
|
||
suggestedFeeRecipient = mkOption { | ||
type = types.nullOr types.str; | ||
default = null; | ||
description = mdDoc '' | ||
Wallet address where transaction fee tips - priority fees, | ||
unburnt portion of gas fees - will be sent. | ||
''; | ||
}; | ||
|
||
listenPort = mkOption { | ||
type = types.port; | ||
default = 9000; | ||
description = mdDoc "Listen port for libp2p protocol."; | ||
}; | ||
|
||
discoverPort = mkOption { | ||
type = types.port; | ||
default = 9000; | ||
description = mdDoc "Listen port for libp2p protocol."; | ||
}; | ||
|
||
nat = mkOption { | ||
type = types.str; | ||
default = "any"; | ||
example = "extip:12.34.56.78"; | ||
description = literalMD '' | ||
Method for determining public address. (any, none, upnp, pmp, extip:<IP>) | ||
''; | ||
}; | ||
|
||
metrics = { | ||
enable = lib.mkEnableOption (mdDoc "Nimbus beacon node metrics endpoint"); | ||
address = mkOption { | ||
type = types.str; | ||
default = "127.0.0.1"; | ||
description = mdDoc "Metrics address for beacon node."; | ||
}; | ||
port = mkOption { | ||
type = types.port; | ||
default = 9100; | ||
description = mdDoc "Metrics port for beacon node."; | ||
}; | ||
}; | ||
|
||
rest = { | ||
enable = lib.mkEnableOption (mdDoc "Nimbus beacon node REST API"); | ||
address = mkOption { | ||
type = types.str; | ||
default = "127.0.0.1"; | ||
description = mdDoc "Listening address of the REST API server."; | ||
}; | ||
|
||
port = mkOption { | ||
type = types.port; | ||
default = 5052; | ||
description = mdDoc "Port for the REST API server."; | ||
}; | ||
}; | ||
|
||
extraArgs = mkOption { | ||
type = types.listOf types.str; | ||
default = []; | ||
example = ["--num-threads=1" "--graffiti=1337_h4x0r"]; | ||
description = mdDoc "Additional arguments passed to node."; | ||
}; | ||
}; | ||
}; | ||
}; | ||
|
||
config = mkIf cfg.enable { | ||
assertions = [ | ||
{ assertion = length cfg.web3Urls > 0; | ||
message = "Nimbus beacon node requires at least one Web3 URL in services.nimbus-beacon-node.web3Urls to work!"; } | ||
]; | ||
|
||
users.users = optionalAttrs (cfg.service.user == "nimbus") { | ||
nimbus = { | ||
group = cfg.service.group; | ||
home = cfg.dataDir; | ||
description = "Nimbus beacon node service user"; | ||
isSystemUser = true; | ||
}; | ||
}; | ||
|
||
users.groups = optionalAttrs (cfg.service.user == "nimbus") { | ||
nimbus = { }; | ||
}; | ||
|
||
systemd.services.nimbus-beacon-node = { | ||
description = "Nimbus Beacon Node (Ethereum consensus client)"; | ||
|
||
serviceConfig = mkMerge [{ | ||
User = cfg.service.user; | ||
Group = cfg.service.group; | ||
|
||
ExecStart = concatStringsSep " \\\n " ([ | ||
"${cfg.package}/bin/nimbus_beacon_node" | ||
"--network=${cfg.network}" | ||
"--data-dir=${cfg.dataDir}" | ||
"--log-level=${toUpper cfg.log.level}" | ||
"--log-format=${cfg.log.format}" | ||
"--nat=${cfg.nat}" | ||
"--tcp-port=${toString cfg.listenPort}" | ||
"--udp-port=${toString cfg.discoverPort}" | ||
"--subscribe-all-subnets=${boolToString cfg.subAllSubnets}" | ||
"--doppelganger-detection=${boolToString cfg.doppelganger}" | ||
"--rest=${boolToString cfg.rest.enable}" | ||
] ++ optionals cfg.rest.enable [ | ||
"--rest-address=${cfg.rest.address}" | ||
"--rest-port=${toString cfg.rest.port}" | ||
] ++ [ | ||
"--metrics=${boolToString cfg.metrics.enable}" | ||
] ++ optionals cfg.metrics.enable [ | ||
"--metrics-address=${cfg.metrics.address}" | ||
"--metrics-port=${toString cfg.metrics.port}" | ||
] ++ (forEach cfg.web3Urls (u: "--web3-url=${u}")) | ||
++ optionals (cfg.jwtSecret != null) ["--jwt-secret=${cfg.jwtSecret}"] | ||
++ optionals (cfg.suggestedFeeRecipient != null) ["--suggested-fee-recipient=${cfg.suggestedFeeRecipient}"] | ||
++ (forEach cfg.extraArgs escapeShellArg)); | ||
|
||
WorkingDirectory = cfg.dataDir; | ||
TimeoutSec = 1200; | ||
Restart = "on-failure"; | ||
# Don't restart when Doppelganger detection has been activated | ||
RestartPreventExitStatus = 129; | ||
} | ||
(mkIf (cfg.dataDir == "/var/lib/nimbus-beacon-node") { | ||
StateDirectory = "nimbus-beacon-node"; | ||
StateDirectoryMode = "0750"; | ||
})]; | ||
wantedBy = [ "multi-user.target" ]; | ||
requires = [ "network.target" ]; | ||
}; | ||
}; | ||
|
||
meta = { | ||
doc = ./beacon-node.xml; | ||
maintainers = with lib.maintainers; [ jakubgs ]; | ||
}; | ||
} |
Oops, something went wrong.