reth_cli_util/
load_secret_key.rs1use reth_fs_util::{self as fs, FsPathError};
2use secp256k1::{Error as SecretKeyBaseError, SecretKey};
3use std::{
4 io,
5 path::{Path, PathBuf},
6};
7use thiserror::Error;
8
9pub fn rng_secret_key() -> SecretKey {
11 SecretKey::new(&mut rand_08::thread_rng())
12}
13
14#[derive(Error, Debug)]
16pub enum SecretKeyError {
17 #[error(transparent)]
19 SecretKeyDecodeError(#[from] SecretKeyBaseError),
20
21 #[error(transparent)]
23 SecretKeyFsPathError(#[from] FsPathError),
24
25 #[error("failed to access key file {secret_file:?}: {error}")]
27 FailedToAccessKeyFile {
28 error: io::Error,
30 secret_file: PathBuf,
32 },
33
34 #[error("invalid hex string: {0}")]
36 InvalidHexString(String),
37}
38
39pub fn get_secret_key(secret_key_path: &Path) -> Result<SecretKey, SecretKeyError> {
43 let exists = secret_key_path.try_exists();
44
45 match exists {
46 Ok(true) => {
47 let contents = fs::read_to_string(secret_key_path)?;
48 Ok(contents.as_str().parse().map_err(SecretKeyError::SecretKeyDecodeError)?)
49 }
50 Ok(false) => {
51 if let Some(dir) = secret_key_path.parent() {
52 fs::create_dir_all(dir)?;
54 }
55
56 let secret = rng_secret_key();
57 let hex = alloy_primitives::hex::encode(secret.as_ref());
58 fs::write(secret_key_path, hex)?;
59 Ok(secret)
60 }
61 Err(error) => Err(SecretKeyError::FailedToAccessKeyFile {
62 error,
63 secret_file: secret_key_path.to_path_buf(),
64 }),
65 }
66}
67
68pub fn parse_secret_key_from_hex(hex_str: &str) -> Result<SecretKey, SecretKeyError> {
72 let hex_str = hex_str.strip_prefix("0x").unwrap_or(hex_str);
74
75 let bytes = alloy_primitives::hex::decode(hex_str)
77 .map_err(|e| SecretKeyError::InvalidHexString(e.to_string()))?;
78
79 SecretKey::from_slice(&bytes).map_err(SecretKeyError::SecretKeyDecodeError)
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn test_parse_secret_key_from_hex_without_prefix() {
89 let hex = "4c0883a69102937d6231471b5dbb6204fe512961708279f8c5c58b3b9c4e8b8f";
91 let result = parse_secret_key_from_hex(hex);
92 assert!(result.is_ok());
93
94 let secret_key = result.unwrap();
95 assert_eq!(alloy_primitives::hex::encode(secret_key.secret_bytes()), hex);
96 }
97
98 #[test]
99 fn test_parse_secret_key_from_hex_with_0x_prefix() {
100 let hex = "0x4c0883a69102937d6231471b5dbb6204fe512961708279f8c5c58b3b9c4e8b8f";
102 let result = parse_secret_key_from_hex(hex);
103 assert!(result.is_ok());
104
105 let secret_key = result.unwrap();
106 let expected = "4c0883a69102937d6231471b5dbb6204fe512961708279f8c5c58b3b9c4e8b8f";
107 assert_eq!(alloy_primitives::hex::encode(secret_key.secret_bytes()), expected);
108 }
109
110 #[test]
111 fn test_parse_secret_key_from_hex_invalid_length() {
112 let hex = "4c0883a69102937d";
114 let result = parse_secret_key_from_hex(hex);
115 assert!(result.is_err());
116 }
117
118 #[test]
119 fn test_parse_secret_key_from_hex_invalid_chars() {
120 let hex = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz";
122 let result = parse_secret_key_from_hex(hex);
123 assert!(result.is_err());
124
125 if let Err(SecretKeyError::InvalidHexString(_)) = result {
126 } else {
128 panic!("Expected InvalidHexString error");
129 }
130 }
131
132 #[test]
133 fn test_parse_secret_key_from_hex_empty() {
134 let hex = "";
135 let result = parse_secret_key_from_hex(hex);
136 assert!(result.is_err());
137 }
138}