diff --git a/firewood/src/merkle.rs b/firewood/src/merkle.rs index 50457e7c0..2469ed15d 100644 --- a/firewood/src/merkle.rs +++ b/firewood/src/merkle.rs @@ -1293,6 +1293,15 @@ impl + Send + Sync, T> Merkle { last_key: Option, limit: Option, ) -> Result, Vec>>, api::Error> { + if let (Some(k1), Some(k2)) = (&first_key, &last_key) { + if k1.as_ref() > k2.as_ref() { + return Err(api::Error::InvalidRange { + first_key: k1.as_ref().to_vec(), + last_key: k2.as_ref().to_vec(), + }); + } + } + // limit of 0 is always an empty RangeProof if limit == Some(0) { return Ok(None); @@ -1700,6 +1709,26 @@ mod tests { .is_none()); } + #[tokio::test] + async fn range_proof_invalid_bounds() { + let merkle = create_test_merkle(); + let root = merkle.init_root().unwrap(); + let start_key = &[0x01]; + let end_key = &[0x00]; + + match merkle + .range_proof::<&[u8]>(root, Some(start_key), Some(end_key), Some(1)) + .await + { + Err(api::Error::InvalidRange { + first_key, + last_key, + }) if first_key == start_key && last_key == end_key => (), + Err(api::Error::InvalidRange { .. }) => panic!("wrong bounds on InvalidRange error"), + _ => panic!("expected InvalidRange error"), + } + } + #[tokio::test] async fn full_range_proof() { let mut merkle = create_test_merkle(); diff --git a/firewood/src/v2/api.rs b/firewood/src/v2/api.rs index f0787d785..866ccadd6 100644 --- a/firewood/src/v2/api.rs +++ b/firewood/src/v2/api.rs @@ -64,6 +64,13 @@ pub enum Error { #[error("Incorrect root hash for commit: {provided:?} != {current:?}")] IncorrectRootHash { provided: HashKey, current: HashKey }, + /// Invalid range + #[error("Invalid range: {first_key:?} > {last_key:?}")] + InvalidRange { + first_key: Vec, + last_key: Vec, + }, + #[error("IO error: {0}")] IO(std::io::Error),