Skip to content

Commit

Permalink
Support negative heights in HashOrHeight
Browse files Browse the repository at this point in the history
  • Loading branch information
upbqdn committed Mar 7, 2025
1 parent de7e5b5 commit b38e56f
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 7 deletions.
10 changes: 5 additions & 5 deletions zebra-rpc/src/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -839,11 +839,11 @@ where
None
};

let hash_or_height: HashOrHeight = hash_or_height
.parse()
// Reference for the legacy error code:
// <https://github.com/zcash/zcash/blob/99ad6fdc3a549ab510422820eea5e5ce9f60a5fd/src/rpc/blockchain.cpp#L629>
.map_error(server::error::LegacyCode::InvalidParameter)?;
let hash_or_height =
HashOrHeight::new(&hash_or_height, self.latest_chain_tip.best_tip_height())
// Reference for the legacy error code:
// <https://github.com/zcash/zcash/blob/99ad6fdc3a549ab510422820eea5e5ce9f60a5fd/src/rpc/blockchain.cpp#L629>
.map_error(server::error::LegacyCode::InvalidParameter)?;

if verbosity == 0 {
let request = zebra_state::ReadRequest::Block(hash_or_height);
Expand Down
36 changes: 34 additions & 2 deletions zebra-state/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
use std::{
collections::{HashMap, HashSet},
ops::{Deref, DerefMut, RangeInclusive},
ops::{Add, Deref, DerefMut, RangeInclusive},
sync::Arc,
};

use zebra_chain::{
amount::{Amount, NegativeAllowed, NonNegative},
block::{self, Block},
block::{self, Block, HeightDiff},
history_tree::HistoryTree,
orchard,
parallel::tree::NoteCommitmentTrees,
Expand Down Expand Up @@ -133,6 +133,38 @@ impl HashOrHeight {
None
}
}

/// Constructs a new [`HashOrHeight`] from a string containing a hash or a positive or negative
/// height.
///
/// When the provided `hash_or_height` contains a negative height, the `tip_height` parameter
/// needs to be `Some` since height `-1` points to the tip.
pub fn new(hash_or_height: &str, tip_height: Option<block::Height>) -> Result<Self, String> {
hash_or_height
.parse()
.map(Self::Hash)
.or_else(|_| hash_or_height.parse().map(Self::Height))
.or_else(|_| {
hash_or_height
.parse()
.map_err(|_| "could not parse negative height")
.and_then(|d: HeightDiff| {
d.is_negative()
.then(|| {
Ok(HashOrHeight::Height(
tip_height
.ok_or("missing tip height")?
.add(d)
.ok_or("underflow when adding negative height to tip")?
.next()
.map_err(|_| "height -1 needs to point to tip")?,
))
})
.unwrap_or(Err("height was not negative"))
})
})
.map_err(|e| format!("could not convert the input string to a hash or height: {e}"))
}
}

impl std::fmt::Display for HashOrHeight {
Expand Down

0 comments on commit b38e56f

Please sign in to comment.