diff --git a/crates/primitives/src/prune/target.rs b/crates/primitives/src/prune/target.rs index 2fd9c0f29e..1300b9b0b9 100644 --- a/crates/primitives/src/prune/target.rs +++ b/crates/primitives/src/prune/target.rs @@ -1,7 +1,5 @@ -use crate::{ - serde_helper::deserialize_opt_prune_mode_with_min_blocks, PruneMode, ReceiptsLogPruneConfig, -}; -use serde::{Deserialize, Serialize}; +use crate::{PruneMode, ReceiptsLogPruneConfig}; +use serde::{Deserialize, Deserializer, Serialize}; /// Minimum distance from the tip necessary for the node to work correctly: /// 1. Minimum 2 epochs (32 blocks per epoch) required to handle any reorg according to the @@ -65,3 +63,64 @@ impl PruneModes { } } } + +/// Deserializes [`Option`] and validates that the value is not less than the const +/// generic parameter `MIN_BLOCKS`. This parameter represents the number of blocks that needs to be +/// left in database after the pruning. +/// +/// 1. For [PruneMode::Full], it fails if `MIN_BLOCKS > 0`. +/// 2. For [PruneMode::Distance(distance)], it fails if `distance < MIN_BLOCKS + 1`. `+ 1` is needed +/// because `PruneMode::Distance(0)` means that we leave zero blocks from the latest, meaning we +/// have one block in the database. +fn deserialize_opt_prune_mode_with_min_blocks<'de, const MIN_BLOCKS: u64, D: Deserializer<'de>>( + deserializer: D, +) -> Result, D::Error> { + let prune_mode = Option::::deserialize(deserializer)?; + + match prune_mode { + Some(PruneMode::Full) if MIN_BLOCKS > 0 => { + Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Str("full"), + // This message should have "expected" wording + &format!("prune mode that leaves at least {MIN_BLOCKS} blocks in the database") + .as_str(), + )) + } + Some(PruneMode::Distance(distance)) if distance < MIN_BLOCKS => { + Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Unsigned(distance), + // This message should have "expected" wording + &format!("prune mode that leaves at least {MIN_BLOCKS} blocks in the database") + .as_str(), + )) + } + _ => Ok(prune_mode), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use assert_matches::assert_matches; + use serde::Deserialize; + + #[test] + fn test_deserialize_opt_prune_mode_with_min_blocks() { + #[derive(Debug, Deserialize, PartialEq, Eq)] + struct V( + #[serde(deserialize_with = "deserialize_opt_prune_mode_with_min_blocks::<10, _>")] + Option, + ); + + assert!(serde_json::from_str::(r#"{"distance": 10}"#).is_ok()); + assert_matches!( + serde_json::from_str::(r#"{"distance": 9}"#), + Err(err) if err.to_string() == "invalid value: integer `9`, expected prune mode that leaves at least 10 blocks in the database" + ); + + assert_matches!( + serde_json::from_str::(r#""full""#), + Err(err) if err.to_string() == "invalid value: string \"full\", expected prune mode that leaves at least 10 blocks in the database" + ); + } +} diff --git a/crates/primitives/src/serde_helper.rs b/crates/primitives/src/serde_helper.rs new file mode 100644 index 0000000000..b0d041fdcd --- /dev/null +++ b/crates/primitives/src/serde_helper.rs @@ -0,0 +1,3 @@ +//! [serde] utilities. + +pub use reth_rpc_types::serde_helpers::*; diff --git a/crates/primitives/src/serde_helper/mod.rs b/crates/primitives/src/serde_helper/mod.rs deleted file mode 100644 index 2e897ebcda..0000000000 --- a/crates/primitives/src/serde_helper/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! [serde] utilities. - -pub use reth_rpc_types::serde_helpers::*; - -mod prune; -pub use prune::deserialize_opt_prune_mode_with_min_blocks; diff --git a/crates/primitives/src/serde_helper/prune.rs b/crates/primitives/src/serde_helper/prune.rs deleted file mode 100644 index 41656b35a7..0000000000 --- a/crates/primitives/src/serde_helper/prune.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::PruneMode; -use serde::{Deserialize, Deserializer}; - -/// Deserializes [`Option`] and validates that the value is not less than the const -/// generic parameter `MIN_BLOCKS`. This parameter represents the number of blocks that needs to be -/// left in database after the pruning. -/// -/// 1. For [PruneMode::Full], it fails if `MIN_BLOCKS > 0`. -/// 2. For [PruneMode::Distance(distance)], it fails if `distance < MIN_BLOCKS + 1`. `+ 1` is needed -/// because `PruneMode::Distance(0)` means that we leave zero blocks from the latest, meaning we -/// have one block in the database. -pub fn deserialize_opt_prune_mode_with_min_blocks< - 'de, - const MIN_BLOCKS: u64, - D: Deserializer<'de>, ->( - deserializer: D, -) -> Result, D::Error> { - let prune_mode = Option::::deserialize(deserializer)?; - - match prune_mode { - Some(PruneMode::Full) if MIN_BLOCKS > 0 => { - Err(serde::de::Error::invalid_value( - serde::de::Unexpected::Str("full"), - // This message should have "expected" wording - &format!("prune mode that leaves at least {MIN_BLOCKS} blocks in the database") - .as_str(), - )) - } - Some(PruneMode::Distance(distance)) if distance < MIN_BLOCKS => { - Err(serde::de::Error::invalid_value( - serde::de::Unexpected::Unsigned(distance), - // This message should have "expected" wording - &format!("prune mode that leaves at least {MIN_BLOCKS} blocks in the database") - .as_str(), - )) - } - _ => Ok(prune_mode), - } -} - -#[cfg(test)] -mod tests { - use crate::PruneMode; - use assert_matches::assert_matches; - use serde::Deserialize; - - #[test] - fn deserialize_opt_prune_mode_with_min_blocks() { - #[derive(Debug, Deserialize, PartialEq, Eq)] - struct V( - #[serde( - deserialize_with = "super::deserialize_opt_prune_mode_with_min_blocks::<10, _>" - )] - Option, - ); - - assert!(serde_json::from_str::(r#"{"distance": 10}"#).is_ok()); - assert_matches!( - serde_json::from_str::(r#"{"distance": 9}"#), - Err(err) if err.to_string() == "invalid value: integer `9`, expected prune mode that leaves at least 10 blocks in the database" - ); - - assert_matches!( - serde_json::from_str::(r#""full""#), - Err(err) if err.to_string() == "invalid value: string \"full\", expected prune mode that leaves at least 10 blocks in the database" - ); - } -}