diff --git a/config.example.toml b/config.example.toml index ab8b90e1..8ed5b139 100644 --- a/config.example.toml +++ b/config.example.toml @@ -212,19 +212,21 @@ jwt_auth_fail_timeout_seconds = 300 [signer.local.loader] # File: path to the keys file key_path = "./tests/data/keys.example.json" -# ValidatorsDir: format of the keystore (lighthouse, prysm, teku or lodestar) +# ValidatorsDir: format of the keystore (lighthouse, prysm, teku, lodestar, or nimbus) # format = "lighthouse" # ValidatorsDir: full path to the keys directory -# For lighthouse, it's de path to the directory where the `/voting-keystore.json` directories are located. +# For lighthouse, it's the path to the directory where the `` directories are located, under each of which is a `voting-keystore.json` file. # For prysm, it's the path to the `all-accounts.keystore.json` file. # For teku, it's the path to the directory where all `.json` files are located. # For lodestar, it's the path to the directory where all `.json` files are located. +# For nimbus, it's the path to the directory where the `` directories are located, under each of which is a `keystore.json` file. # keys_path = "" # ValidatorsDir: full path to the secrets file/directory -# For lighthouse, it's de path to the directory where the `.json` files are located. +# For lighthouse, it's the path to the directory where the `` files are located. # For prysm, it's the path to the file containing the wallet decryption password. # For teku, it's the path to the directory where all `.txt` files are located. # For lodestar, it's the path to the file containing the decryption password. +# For nimbus, it's the path to the directory where the `` files are located. # secrets_path = "" # Configuration for how the Signer module should store proxy delegations. Supported types of store are: # - File: store keys and delegations from a plain text file (unsafe, use only for testing purposes) diff --git a/crates/common/src/signer/loader.rs b/crates/common/src/signer/loader.rs index d678795e..4fb9adb1 100644 --- a/crates/common/src/signer/loader.rs +++ b/crates/common/src/signer/loader.rs @@ -47,6 +47,8 @@ pub enum ValidatorKeysFormat { Lodestar, #[serde(alias = "prysm")] Prysm, + #[serde(alias = "nimbus")] + Nimbus, } impl SignerLoader { @@ -85,6 +87,7 @@ impl SignerLoader { load_from_lodestar_format(keys_path, secrets_path) } ValidatorKeysFormat::Prysm => load_from_prysm_format(keys_path, secrets_path), + ValidatorKeysFormat::Nimbus => load_from_nimbus_format(keys_path, secrets_path), }; } }) @@ -272,6 +275,42 @@ fn load_from_prysm_format( Ok(signers) } +fn load_from_nimbus_format( + keys_path: PathBuf, + secrets_path: PathBuf, +) -> eyre::Result> { + let paths: Vec<_> = + fs::read_dir(&keys_path)?.map(|res| res.map(|e| e.path())).collect::>()?; + + let signers = paths + .into_par_iter() + .filter_map(|path| { + if !path.is_dir() { + return None + } + + let maybe_pubkey = path.file_name().and_then(|d| d.to_str())?; + let Ok(pubkey) = BlsPublicKey::from_hex(maybe_pubkey) else { + warn!("Invalid pubkey: {}", maybe_pubkey); + return None + }; + + let ks_path = keys_path.join(maybe_pubkey).join("keystore.json"); + let pw_path = secrets_path.join(pubkey.to_string()); + + match load_one(ks_path, pw_path) { + Ok(signer) => Some(signer), + Err(e) => { + warn!("Failed to load signer for pubkey: {}, err: {}", pubkey, e); + None + } + } + }) + .collect(); + + Ok(signers) +} + fn load_one(ks_path: PathBuf, pw_path: PathBuf) -> eyre::Result { let keystore = Keystore::from_json_file(ks_path).map_err(|_| eyre!("failed reading json"))?; let password = fs::read(pw_path.clone()) @@ -303,7 +342,7 @@ mod tests { use super::{load_from_lighthouse_format, load_from_lodestar_format, FileKey}; use crate::signer::{ - loader::{load_from_prysm_format, load_from_teku_format}, + loader::{load_from_nimbus_format, load_from_prysm_format, load_from_teku_format}, BlsPublicKey, BlsSigner, }; @@ -399,4 +438,16 @@ mod tests { hex!("b3a22e4a673ac7a153ab5b3c17a4dbef55f7e47210b20c0cbb0e66df5b36bb49ef808577610b034172e955d2312a61b9") ))); } + + #[test] + fn test_load_nimbus() { + let result = load_from_nimbus_format( + "../../tests/data/keystores/nimbus-keys".into(), + "../../tests/data/keystores/secrets".into(), + ); + + assert!(result.is_ok()); + + test_correct_load(result.unwrap()); + } } diff --git a/docs/docs/get_started/configuration.md b/docs/docs/get_started/configuration.md index 5dd46329..c3f49712 100644 --- a/docs/docs/get_started/configuration.md +++ b/docs/docs/get_started/configuration.md @@ -52,7 +52,7 @@ keys_path = "/path/to/keys" secrets_path = "/path/to.secrets" ``` -We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's easier to load the keys. We're working on adding support for additional keystores. These are the expected file structures for each format: +We currently support Lighthouse, Prysm, Teku, Lodestar, and Nimbus's keystores so it's easier to load the keys. We're working on adding support for additional keystores. These are the expected file structures for each format:
Lighthouse @@ -175,6 +175,37 @@ We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's ea :::
+
+ Nimbus + + #### File structure: + ``` + ├── keys + │   ├── + │   │   └── keystore.json + │   └── + │   └── keystore.json + └── secrets +    ├── +    └── + ``` + + #### Config: + ```toml + [pbs] + ... + with_signer = true + + [signer] + port = 20000 + + [signer.local.loader] + format = "nimbus" + keys_path = "keys" + secrets_path = "secrets" + ``` +
+ ### Proxy keys store Proxy keys can be used to sign transactions with a different key than the one used to sign the block. Proxy keys are generated by the Signer module and authorized by the validator key. Each module have their own proxy keys, that can be BLS or ECDSA. diff --git a/tests/data/keystores/nimbus-keys/0x883827193f7627cd04e621e1e8d56498362a52b2a30c9a1c72036eb935c4278dee23d38a24d2f7dda62689886f0c39f4/keystore.json b/tests/data/keystores/nimbus-keys/0x883827193f7627cd04e621e1e8d56498362a52b2a30c9a1c72036eb935c4278dee23d38a24d2f7dda62689886f0c39f4/keystore.json new file mode 100644 index 00000000..72b13cad --- /dev/null +++ b/tests/data/keystores/nimbus-keys/0x883827193f7627cd04e621e1e8d56498362a52b2a30c9a1c72036eb935c4278dee23d38a24d2f7dda62689886f0c39f4/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"0ded1a0ed9d0d5aa9c41ac1a6be6d9943835f9ccbe1081869af74925611a4687"},"message":""},"checksum":{"function":"sha256","params":{},"message":"b1de458543b0532666e8f24e679f93ed6f168fd09de1da7c3f4f79b7fa2f2412"},"cipher":{"function":"aes-128-ctr","params":{"iv":"3ca34eb318e53a4c7e545571d8d0c7af"},"message":"acc6c222eea80974107b5a9bf824c8156edaad944f0d444a1aab4cc2118cecc5"}},"description":"0x883827193f7627cd04e621e1e8d56498362a52b2a30c9a1c72036eb935c4278dee23d38a24d2f7dda62689886f0c39f4","pubkey":"883827193f7627cd04e621e1e8d56498362a52b2a30c9a1c72036eb935c4278dee23d38a24d2f7dda62689886f0c39f4","path":"","uuid":"61c06c9c-b0bc-4022-9bf8-a2f250d4e751","version":4} \ No newline at end of file diff --git a/tests/data/keystores/nimbus-keys/0xb3a22e4a673ac7a153ab5b3c17a4dbef55f7e47210b20c0cbb0e66df5b36bb49ef808577610b034172e955d2312a61b9/keystore.json b/tests/data/keystores/nimbus-keys/0xb3a22e4a673ac7a153ab5b3c17a4dbef55f7e47210b20c0cbb0e66df5b36bb49ef808577610b034172e955d2312a61b9/keystore.json new file mode 100644 index 00000000..ba717c1c --- /dev/null +++ b/tests/data/keystores/nimbus-keys/0xb3a22e4a673ac7a153ab5b3c17a4dbef55f7e47210b20c0cbb0e66df5b36bb49ef808577610b034172e955d2312a61b9/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"2154bba4d5999c6069442db5b499b2b27b6c2f54f36490e51163934dd4fb412e"},"message":""},"checksum":{"function":"sha256","params":{},"message":"1db4975098c97905f1dd9a9207cab0a9af7e16bebdab700ee08efb51e068017f"},"cipher":{"function":"aes-128-ctr","params":{"iv":"2265a3b57110b46c08295e53379165b5"},"message":"3bd312cc34cebfdd890c9704752191ed93ecd562bb62d2d8ceb4ff945b58b790"}},"description":"0xb3a22e4a673ac7a153ab5b3c17a4dbef55f7e47210b20c0cbb0e66df5b36bb49ef808577610b034172e955d2312a61b9","pubkey":"b3a22e4a673ac7a153ab5b3c17a4dbef55f7e47210b20c0cbb0e66df5b36bb49ef808577610b034172e955d2312a61b9","path":"","uuid":"a8457299-739d-42fb-a0f6-961020f22b8e","version":4} \ No newline at end of file