Skip to content

Commit

Permalink
fix(rust): Interpret max_depth in proof specs as 128 if left to 0
Browse files Browse the repository at this point in the history
  • Loading branch information
romac committed Sep 18, 2024
1 parent 6302484 commit 4fa4e3e
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 23 deletions.
63 changes: 63 additions & 0 deletions rust/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,69 @@ mod tests {
verify_test_vector("../testdata/smt/nonexist_middle.json", &spec)
}

#[derive(Deserialize)]
#[serde(rename_all = "PascalCase")]
struct ExistenceProofTest {
proof: crate::ExistenceProof,
is_err: bool,
expected: Option<Vec<u8>>,
}

#[test]
#[cfg(feature = "std")]
fn test_existence_proof() -> Result<()> {
use crate::calculate_existence_root;

let data = std::fs::read_to_string("../testdata/TestExistenceProofData.json")?;
let tests: BTreeMap<String, ExistenceProofTest> = serde_json::from_str(&data)?;

for (name, test) in tests {
println!("Test: {name}");
let result = calculate_existence_root::<HostFunctionsManager>(&test.proof);
if test.is_err {
assert!(result.is_err());
} else {
assert!(result.is_ok());
assert_eq!(
result.unwrap().as_slice(),
test.expected.unwrap().as_slice()
);
}
}

Ok(())
}

#[derive(Deserialize)]
#[serde(rename_all = "PascalCase")]
struct CheckAgainstSpecTest {
proof: crate::ExistenceProof,
spec: crate::ProofSpec,
err: String,
}

#[test]
#[cfg(feature = "std")]
fn test_check_against_spec() -> Result<()> {
use crate::verify::check_existence_spec;

let data = std::fs::read_to_string("../testdata/TestCheckAgainstSpecData.json")?;
let tests: BTreeMap<String, CheckAgainstSpecTest> = serde_json::from_str(&data)?;

for (name, test) in tests {
println!("Test: {name}");
let result = check_existence_spec(&test.proof, &test.spec);
if test.err.is_empty() {
assert!(result.is_ok());
} else {
assert!(result.is_err());
// assert_eq!(result.unwrap_err().to_string(), test.err);
}
}

Ok(())
}

#[cfg(feature = "std")]
fn load_batch(files: &[&str]) -> Result<(ics23::CommitmentProof, Vec<RefData>)> {
let (data, entries) = files
Expand Down
4 changes: 4 additions & 0 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ mod verify;
mod ics23 {
include!("cosmos.ics23.v1.rs");

impl ProofSpec {
pub const DEFAULT_MAX_DEPTH: i32 = 128;
}

#[cfg(feature = "serde")]
include!("cosmos.ics23.v1.serde.rs");
}
Expand Down
62 changes: 39 additions & 23 deletions rust/src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,31 +114,47 @@ fn calculate_existence_root_for_spec<H: HostFunctionsProvider>(
}
}

fn check_existence_spec(proof: &ics23::ExistenceProof, spec: &ics23::ProofSpec) -> Result<()> {
if let (Some(leaf), Some(leaf_spec)) = (&proof.leaf, &spec.leaf_spec) {
ensure_leaf_prefix(&leaf.prefix, spec)?;
ensure_leaf(leaf, leaf_spec)?;
// ensure min/max depths
if spec.min_depth != 0 {
ensure!(
proof.path.len() >= spec.min_depth as usize,
"Too few InnerOps: {}",
proof.path.len(),
);
ensure!(
proof.path.len() <= spec.max_depth as usize,
"Too many InnerOps: {}",
proof.path.len(),
);
}
for (idx, step) in proof.path.iter().enumerate() {
ensure_inner_prefix(&step.prefix, spec, (idx as i64) + 1, step.hash)?;
ensure_inner(step, spec)?;
}
Ok(())
pub(crate) fn check_existence_spec(
proof: &ics23::ExistenceProof,
spec: &ics23::ProofSpec,
) -> Result<()> {
let Some(leaf) = &proof.leaf else {
bail!("existence Proof needs defined LeafOp");
};

let Some(leaf_spec) = &spec.leaf_spec else {
bail!("existence Proof needs defined LeafSpec");
};

ensure_leaf_prefix(&leaf.prefix, spec)?;
ensure_leaf(leaf, leaf_spec)?;

let max_depth = if spec.max_depth == 0 {
ics23::ProofSpec::DEFAULT_MAX_DEPTH
} else {
bail!("Leaf and Leaf Spec must be set")
spec.max_depth
};

// ensure min/max depths
if spec.min_depth != 0 {
ensure!(
proof.path.len() >= spec.min_depth as usize,
"innerOps depth too short: {}",
proof.path.len(),
);
ensure!(
proof.path.len() <= max_depth as usize,
"innerOps depth too long: {}",
proof.path.len(),
);
}

for (idx, step) in proof.path.iter().enumerate() {
ensure_inner_prefix(&step.prefix, spec, (idx as i64) + 1, step.hash)?;
ensure_inner(step, spec)?;
}

Ok(())
}

fn ensure_leaf(leaf: &ics23::LeafOp, leaf_spec: &ics23::LeafOp) -> Result<()> {
Expand Down

0 comments on commit 4fa4e3e

Please sign in to comment.