diff --git a/Cargo.toml b/Cargo.toml index f68b350..67fd6e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jmt" -version = "0.4.2" +version = "0.5.0" authors = [ "Penumbra Labs ", "Diem Association ", diff --git a/src/tree/ics23_impl.rs b/src/tree/ics23_impl.rs index be079fb..bbe510a 100644 --- a/src/tree/ics23_impl.rs +++ b/src/tree/ics23_impl.rs @@ -7,7 +7,8 @@ use crate::{ storage::HasPreimage, storage::TreeReader, tree::ExclusionProof, - JellyfishMerkleTree, KeyHash, SimpleHasher, Version, SPARSE_MERKLE_PLACEHOLDER_HASH, + JellyfishMerkleTree, KeyHash, OwnedValue, SimpleHasher, Version, + SPARSE_MERKLE_PLACEHOLDER_HASH, }; fn sparse_merkle_proof_to_ics23_existence_proof( @@ -185,12 +186,14 @@ where } } - /// Returns the value and an [`JMTProof`]. + /// Returns the value corresponding to the specified key (if there is a value associated with it) + /// along with an [ics23::CommitmentProof] proving either the presence of the value at that key, + /// or the absence of any value at that key, depending on which is the case. pub fn get_with_ics23_proof( &self, key: Vec, version: Version, - ) -> Result { + ) -> Result<(Option, ics23::CommitmentProof)> { let key_hash: KeyHash = KeyHash::with::(key.as_slice()); let proof_or_exclusion = self.get_with_exclusion_proof(key_hash, version)?; @@ -199,9 +202,12 @@ where let ics23_exist = sparse_merkle_proof_to_ics23_existence_proof(key, value.clone(), &proof); - Ok(ics23::CommitmentProof { - proof: Some(ics23::commitment_proof::Proof::Exist(ics23_exist)), - }) + Ok(( + Some(value), + ics23::CommitmentProof { + proof: Some(ics23::commitment_proof::Proof::Exist(ics23_exist)), + }, + )) } Err(exclusion_proof) => { let ics23_nonexist = self.exclusion_proof_to_ics23_nonexistence_proof( @@ -210,9 +216,12 @@ where &exclusion_proof, )?; - Ok(ics23::CommitmentProof { - proof: Some(ics23::commitment_proof::Proof::Nonexist(ics23_nonexist)), - }) + Ok(( + None, + ics23::CommitmentProof { + proof: Some(ics23::commitment_proof::Proof::Nonexist(ics23_nonexist)), + }, + )) } } } @@ -288,7 +297,8 @@ mod tests { let (new_root_hash, batch) = tree.put_value_set(kvs, 0).unwrap(); db.write_tree_update_batch(batch).unwrap(); - let commitment_proof = tree.get_with_ics23_proof(b"notexist".to_vec(), 0).unwrap(); + let (value_retrieved, commitment_proof) = + tree.get_with_ics23_proof(b"notexist".to_vec(), 0).unwrap(); let key_hash = KeyHash::with::(b"notexist".as_slice()); let proof_or_exclusion = tree.get_with_exclusion_proof(key_hash, 0).unwrap(); @@ -313,7 +323,9 @@ mod tests { &ics23_spec(), &new_root_hash.0.to_vec(), b"notexist" - )) + )); + + assert_eq!(value_retrieved, None) } Rightmost { rightmost_left_proof, @@ -331,7 +343,9 @@ mod tests { &ics23_spec(), &new_root_hash.0.to_vec(), b"notexist" - )) + )); + + assert_eq!(value_retrieved, None) } Middle { leftmost_right_proof, @@ -358,7 +372,9 @@ mod tests { &ics23_spec(), &new_root_hash.0.to_vec(), b"notexist" - )) + )); + + assert_eq!(value_retrieved, None) } }, } @@ -392,7 +408,8 @@ mod tests { let (new_root_hash, batch) = tree.put_value_set(kvs, 0).unwrap(); db.write_tree_update_batch(batch).unwrap(); - let commitment_proof = tree.get_with_ics23_proof(b"key".to_vec(), 0).unwrap(); + let (value_retrieved, commitment_proof) = + tree.get_with_ics23_proof(b"key".to_vec(), 0).unwrap(); assert!(ics23::verify_membership::( &commitment_proof, @@ -401,6 +418,8 @@ mod tests { b"key", b"value", )); + + assert_eq!(value_retrieved.unwrap(), b"value"); } #[test] @@ -419,7 +438,9 @@ mod tests { db.write_tree_update_batch(batch).unwrap(); } - let commitment_proof = tree + let value_maxversion = format!("value{}", MAX_VERSION).into_bytes(); + + let (value_retrieved, commitment_proof) = tree .get_with_ics23_proof(format!("key{}", MAX_VERSION).into_bytes(), MAX_VERSION) .unwrap(); @@ -432,5 +453,7 @@ mod tests { format!("key{}", MAX_VERSION).as_bytes(), format!("value{}", MAX_VERSION).as_bytes(), )); + + assert_eq!(value_retrieved.unwrap(), value_maxversion); } }