소스 검색

sdk/monotree: replace expect() panics with propagated errrors

oars 3 달 전
부모
커밋
15d70323cb
7개의 변경된 파일116개의 추가작업 그리고 76개의 파일을 삭제
  1. 2 2
      src/blockchain/contract_store.rs
  2. 12 0
      src/sdk/src/error.rs
  3. 8 8
      src/sdk/src/monotree/bits.rs
  4. 4 3
      src/sdk/src/monotree/node.rs
  5. 16 16
      src/sdk/src/monotree/tests.rs
  6. 55 29
      src/sdk/src/monotree/tree.rs
  7. 19 18
      src/sdk/src/monotree/utils.rs

+ 2 - 2
src/blockchain/contract_store.rs

@@ -612,7 +612,7 @@ impl ContractStoreOverlay {
             }
 
             // Set root
-            monotree.set_headroot(monotree_root.as_ref());
+            monotree.set_headroot(monotree_root.as_ref())?;
 
             // Keep track of the new root for the main monotree
             let monotree_root = match monotree_root {
@@ -645,7 +645,7 @@ impl ContractStoreOverlay {
         }
 
         // Set new global root
-        monotree.set_headroot(monotree_root.as_ref());
+        monotree.set_headroot(monotree_root.as_ref())?;
 
         // Return its hash
         let monotree_root = match monotree_root {

+ 12 - 0
src/sdk/src/error.rs

@@ -95,6 +95,12 @@ pub enum ContractError {
 
     #[error("Hex string is not properly formatted")]
     HexFmtErr,
+
+    #[error("Numcast: cast failed")]
+    NumCastError,
+
+    #[error("Monotree error: {0}")]
+    MonotreeError(String),
 }
 
 /// Builtin return values occupy the upper 32 bits
@@ -126,6 +132,8 @@ pub const SMT_DEL_FAILED: i64 = to_builtin!(19);
 pub const GET_SYSTEM_TIME_FAILED: i64 = to_builtin!(20);
 pub const DATA_TOO_LARGE: i64 = to_builtin!(21);
 pub const HEX_FMT_ERR: i64 = to_builtin!(22);
+pub const NUM_CAST_ERR: i64 = to_builtin!(23);
+pub const MONOTREE_ERROR: i64 = to_builtin!(24);
 
 impl From<ContractError> for i64 {
     fn from(err: ContractError) -> Self {
@@ -151,6 +159,8 @@ impl From<ContractError> for i64 {
             ContractError::GetSystemTimeFailed => GET_SYSTEM_TIME_FAILED,
             ContractError::DataTooLarge => DATA_TOO_LARGE,
             ContractError::HexFmtErr => HEX_FMT_ERR,
+            ContractError::NumCastError => NUM_CAST_ERR,
+            ContractError::MonotreeError(_) => MONOTREE_ERROR,
             ContractError::Custom(error) => {
                 if error == 0 {
                     CUSTOM_ZERO
@@ -187,6 +197,8 @@ impl From<i64> for ContractError {
             GET_SYSTEM_TIME_FAILED => Self::GetSystemTimeFailed,
             DATA_TOO_LARGE => Self::DataTooLarge,
             HEX_FMT_ERR => Self::HexFmtErr,
+            NUM_CAST_ERR => Self::NumCastError,
+            MONOTREE_ERROR => Self::MonotreeError("Unknown".to_string()),
             _ => Self::Custom(error as u32),
         }
     }

+ 8 - 8
src/sdk/src/monotree/bits.rs

@@ -221,11 +221,11 @@ impl<'a> Bits<'a> {
     }
 
     /// Construct `Bits` instance by deserializing bytes slice.
-    pub fn from_bytes(bytes: &'a [u8]) -> Self {
+    pub fn from_bytes(bytes: &'a [u8]) -> GenericResult<Self> {
         let u = std::mem::size_of::<BitsLen>();
-        let start: BitsLen = bytes_to_int(&bytes[..u]);
-        let end: BitsLen = bytes_to_int(&bytes[u..2 * u]);
-        Self { path: &bytes[2 * u..], range: start..end }
+        let start: BitsLen = bytes_to_int(&bytes[..u])?;
+        let end: BitsLen = bytes_to_int(&bytes[u..2 * u])?;
+        Ok(Self { path: &bytes[2 * u..], range: start..end })
     }
 
     /// Serialize `Bits` into bytes.
@@ -261,11 +261,11 @@ impl<'a> Bits<'a> {
     }
 
     /// Get the first `n` bits.
-    pub fn take(&self, n: BitsLen) -> Self {
+    pub fn take(&self, n: BitsLen) -> GenericResult<Self> {
         let x = self.range.start + n;
-        let q = nbytes_across(self.range.start, x);
+        let q = nbytes_across(self.range.start, x)?;
         let range = self.range.start..x;
-        Self { path: &self.path[..q as usize], range }
+        Ok(Self { path: &self.path[..q as usize], range })
     }
 
     /// Skip the first `n` bits.
@@ -277,7 +277,7 @@ impl<'a> Bits<'a> {
     }
 
     /// Get length of the longest common prefix bits for the given two `Bits`.
-    pub fn len_common_bits(a: &Self, b: &Self) -> BitsLen {
+    pub fn len_common_bits(a: &Self, b: &Self) -> GenericResult<BitsLen> {
         len_lcp(a.path, &a.range, b.path, &b.range)
     }
 

+ 4 - 3
src/sdk/src/monotree/node.rs

@@ -105,9 +105,10 @@ impl<'a> Node<'a> {
         let len_bits = std::mem::size_of::<BitsLen>();
         let offset_hash = if right { 0_usize } else { HASH_LEN };
         let range_hash = if right { len_bytes - HASH_LEN..len_bytes } else { 0..HASH_LEN };
-        let start: BitsLen = bytes_to_int(&bytes[offset_hash..offset_hash + len_bits]);
-        let end: BitsLen = bytes_to_int(&bytes[offset_hash + len_bits..offset_hash + 2 * len_bits]);
-        let offset_bits = nbytes_across(start, end) as usize;
+        let start: BitsLen = bytes_to_int(&bytes[offset_hash..offset_hash + len_bits])?;
+        let end: BitsLen =
+            bytes_to_int(&bytes[offset_hash + len_bits..offset_hash + 2 * len_bits])?;
+        let offset_bits = nbytes_across(start, end)? as usize;
 
         Ok((
             Some(Unit {

+ 16 - 16
src/sdk/src/monotree/tests.rs

@@ -34,7 +34,7 @@ fn monotree_test_insert_then_verify_values() {
 
     for (i, (key, value)) in keys.iter().zip(values.iter()).enumerate() {
         root = tree.insert(root.as_ref(), key, value).unwrap();
-        tree.set_headroot(root.as_ref());
+        tree.set_headroot(root.as_ref()).unwrap();
 
         for (k, v) in keys.iter().zip(values.iter()).take(i + 1) {
             assert_eq!(tree.get(root.as_ref(), k).unwrap(), Some(*v));
@@ -55,11 +55,11 @@ fn monotree_test_insert_keys_then_gen_and_verify_proof() {
 
     for (i, (key, value)) in keys.iter().zip(values.iter()).enumerate() {
         root = tree.insert(root.as_ref(), key, value).unwrap();
-        tree.set_headroot(root.as_ref());
+        tree.set_headroot(root.as_ref()).unwrap();
 
         for (k, v) in keys.iter().zip(values.iter()).take(i + 1) {
             let proof = tree.get_merkle_proof(root.as_ref(), k).unwrap();
-            assert!(verify_proof(root.as_ref(), v, proof.as_ref()));
+            assert!(verify_proof(root.as_ref(), v, proof.as_ref()).unwrap());
         }
     }
 
@@ -77,7 +77,7 @@ fn monotree_test_insert_keys_then_delete_keys_in_order() {
 
     // pre-insertion for removal test
     root = tree.inserts(root.as_ref(), &keys, &values).unwrap();
-    tree.set_headroot(root.as_ref());
+    tree.set_headroot(root.as_ref()).unwrap();
 
     // Removal test with keys in order
     for (i, (key, _)) in keys.iter().zip(values.iter()).enumerate() {
@@ -86,12 +86,12 @@ fn monotree_test_insert_keys_then_delete_keys_in_order() {
         for (k, v) in keys.iter().zip(values.iter()).skip(i) {
             assert_eq!(tree.get(root.as_ref(), k).unwrap(), Some(*v));
             let proof = tree.get_merkle_proof(root.as_ref(), k).unwrap();
-            assert!(verify_proof(root.as_ref(), v, proof.as_ref()));
+            assert!(verify_proof(root.as_ref(), v, proof.as_ref()).unwrap());
         }
 
         // Delete a key and check if it worked
         root = tree.remove(root.as_ref(), key).unwrap();
-        tree.set_headroot(root.as_ref());
+        tree.set_headroot(root.as_ref()).unwrap();
         assert_eq!(tree.get(root.as_ref(), key).unwrap(), None);
     }
 
@@ -110,7 +110,7 @@ fn monotree_test_insert_then_delete_keys_reverse() {
 
     // pre-insertion for removal test
     root = tree.inserts(root.as_ref(), &keys, &values).unwrap();
-    tree.set_headroot(root.as_ref());
+    tree.set_headroot(root.as_ref()).unwrap();
 
     // Removal test with keys in reverse order
     for (i, (key, _)) in keys.iter().zip(values.iter()).rev().enumerate() {
@@ -119,12 +119,12 @@ fn monotree_test_insert_then_delete_keys_reverse() {
         for (k, v) in keys.iter().zip(values.iter()).rev().skip(i) {
             assert_eq!(tree.get(root.as_ref(), k).unwrap(), Some(*v));
             let proof = tree.get_merkle_proof(root.as_ref(), k).unwrap();
-            assert!(verify_proof(root.as_ref(), v, proof.as_ref()));
+            assert!(verify_proof(root.as_ref(), v, proof.as_ref()).unwrap());
         }
 
         // Delete a key and check if it worked
         root = tree.remove(root.as_ref(), key).unwrap();
-        tree.set_headroot(root.as_ref());
+        tree.set_headroot(root.as_ref()).unwrap();
         assert_eq!(tree.get(root.as_ref(), key).unwrap(), None);
     }
 
@@ -143,7 +143,7 @@ fn monotree_test_insert_then_delete_keys_random() {
 
     // pre-insertion for removal test
     root = tree.inserts(root.as_ref(), &keys, &values).unwrap();
-    tree.set_headroot(root.as_ref());
+    tree.set_headroot(root.as_ref()).unwrap();
 
     // Shuffles keys/leaves' index for imitating random access
     let mut idx: Vec<usize> = (0..keys.len()).collect();
@@ -157,12 +157,12 @@ fn monotree_test_insert_then_delete_keys_random() {
         for j in idx.iter().skip(n) {
             assert_eq!(tree.get(root.as_ref(), &keys[*j]).unwrap(), Some(values[*j]));
             let proof = tree.get_merkle_proof(root.as_ref(), &keys[*j]).unwrap();
-            assert!(verify_proof(root.as_ref(), &values[*j], proof.as_ref()));
+            assert!(verify_proof(root.as_ref(), &values[*j], proof.as_ref()).unwrap());
         }
 
         // Delete a key by random index and check if it worked
         root = tree.remove(root.as_ref(), &keys[*i]).unwrap();
-        tree.set_headroot(root.as_ref());
+        tree.set_headroot(root.as_ref()).unwrap();
         assert_eq!(tree.get(root.as_ref(), &values[*i]).unwrap(), None);
     }
 
@@ -185,14 +185,14 @@ fn monotree_test_deterministic_ordering() {
 
     // Insert in normal order
     root1 = tree1.inserts(root1.as_ref(), &keys, &values).unwrap();
-    tree1.set_headroot(root1.as_ref());
+    tree1.set_headroot(root1.as_ref()).unwrap();
     assert_ne!(root1, None);
 
     // Insert in reverse order
     let rev_keys: Vec<Hash> = keys.iter().rev().cloned().collect();
     let rev_vals: Vec<Hash> = values.iter().rev().cloned().collect();
     root2 = tree2.inserts(root2.as_ref(), &rev_keys, &rev_vals).unwrap();
-    tree2.set_headroot(root2.as_ref());
+    tree2.set_headroot(root2.as_ref()).unwrap();
     assert_ne!(root2, None);
 
     // Verify roots match
@@ -201,10 +201,10 @@ fn monotree_test_deterministic_ordering() {
     // Verify removal consistency
     for key in keys {
         root1 = tree1.remove(root1.as_ref(), &key).unwrap();
-        tree1.set_headroot(root1.as_ref());
+        tree1.set_headroot(root1.as_ref()).unwrap();
 
         root2 = tree2.remove(root2.as_ref(), &key).unwrap();
-        tree2.set_headroot(root2.as_ref());
+        tree2.set_headroot(root2.as_ref()).unwrap();
 
         assert_eq!(root1, root2);
     }

+ 55 - 29
src/sdk/src/monotree/tree.rs

@@ -335,18 +335,20 @@ impl<D: MonotreeStorageAdapter> Monotree<D> {
     }
 
     /// Sets the latest state (root) to the database.
-    pub fn set_headroot(&mut self, headroot: Option<&Hash>) {
+    pub fn set_headroot(&mut self, headroot: Option<&Hash>) -> GenericResult<()> {
         if let Some(root) = headroot {
-            self.db.put(ROOT_KEY, root.to_vec()).expect("set_headroot(): hash");
+            self.db.put(ROOT_KEY, root.to_vec())?;
         }
+
+        Ok(())
     }
 
-    pub fn prepare(&mut self) {
-        self.db.init_batch().expect("prepare(): failed to initialize batch");
+    pub fn prepare(&mut self) -> GenericResult<()> {
+        self.db.init_batch()
     }
 
-    pub fn commit(&mut self) {
-        self.db.finish_batch().expect("commit(): failed to initialize batch");
+    pub fn commit(&mut self) -> GenericResult<()> {
+        self.db.finish_batch()
     }
 
     /// Insert key-leaf entry into the tree. Returns a new root hash.
@@ -456,10 +458,12 @@ impl<D: MonotreeStorageAdapter> Monotree<D> {
     ///   Immediately split node into two with the longest common prefix,
     ///   then wind the recursive stack from there returning resulting hashes.
     fn put(&mut self, root: &[u8], bits: Bits, leaf: &[u8]) -> GenericResult<Option<Hash>> {
-        let bytes = self.db.get(root)?.expect("put(): bytes");
+        let bytes =
+            self.db.get(root)?.ok_or(ContractError::MonotreeError("put(): bytes".to_string()))?;
         let (left, right) = Node::cells_from_bytes(&bytes, bits.first())?;
-        let unit = left.as_ref().expect("put(): left-unit");
-        let n = Bits::len_common_bits(&unit.bits, &bits);
+        let unit =
+            left.as_ref().ok_or(ContractError::MonotreeError("put(): left-unit".to_string()))?;
+        let n = Bits::len_common_bits(&unit.bits, &bits)?;
 
         match n {
             0 => self.put_node(Node::new(left, Some(Unit { hash: leaf, bits }))),
@@ -467,8 +471,9 @@ impl<D: MonotreeStorageAdapter> Monotree<D> {
                 self.put_node(Node::new(Some(Unit { hash: leaf, bits }), right))
             }
             n if n == unit.bits.len() => {
-                let hash =
-                    &self.put(unit.hash, bits.drop(n), leaf)?.expect("put(): consume & pass-over");
+                let hash = &self.put(unit.hash, bits.drop(n), leaf)?.ok_or(
+                    ContractError::MonotreeError("put(): consume & pass-over".to_string()),
+                )?;
 
                 self.put_node(Node::new(Some(Unit { hash, bits: unit.bits.to_owned() }), right))
             }
@@ -478,9 +483,9 @@ impl<D: MonotreeStorageAdapter> Monotree<D> {
                         Some(Unit { hash: unit.hash, bits: unit.bits.drop(n) }),
                         Some(Unit { hash: leaf, bits: bits.drop(n) }),
                     ))?
-                    .expect("put(): split-node");
+                    .ok_or(ContractError::MonotreeError("put(): split-node".to_string()))?;
 
-                self.put_node(Node::new(Some(Unit { hash, bits: unit.bits.take(n) }), right))
+                self.put_node(Node::new(Some(Unit { hash, bits: unit.bits.take(n)? }), right))
             }
         }
     }
@@ -494,10 +499,15 @@ impl<D: MonotreeStorageAdapter> Monotree<D> {
     }
 
     fn find_key(&mut self, root: &[u8], bits: Bits) -> GenericResult<Option<Hash>> {
-        let bytes = self.db.get(root)?.expect("find_key(): bytes");
+        let bytes = self
+            .db
+            .get(root)?
+            .ok_or(ContractError::MonotreeError("find_key(): bytes".to_string()))?;
         let (cell, _) = Node::cells_from_bytes(&bytes, bits.first())?;
-        let unit = cell.as_ref().expect("find_key(): left-unit");
-        let n = Bits::len_common_bits(&unit.bits, &bits);
+        let unit = cell
+            .as_ref()
+            .ok_or(ContractError::MonotreeError("find_key(): left-unit".to_string()))?;
+        let n = Bits::len_common_bits(&unit.bits, &bits)?;
         match n {
             n if n == bits.len() => Ok(Some(slice_to_hash(unit.hash))),
             n if n == unit.bits.len() => self.find_key(unit.hash, bits.drop(n)),
@@ -514,10 +524,15 @@ impl<D: MonotreeStorageAdapter> Monotree<D> {
     }
 
     fn delete_key(&mut self, root: &[u8], bits: Bits) -> GenericResult<Option<Hash>> {
-        let bytes = self.db.get(root)?.expect("delete_key(): bytes");
+        let bytes = self
+            .db
+            .get(root)?
+            .ok_or(ContractError::MonotreeError("delete_key(): bytes".to_string()))?;
         let (left, right) = Node::cells_from_bytes(&bytes, bits.first())?;
-        let unit = left.as_ref().expect("delete_key(): left-unit");
-        let n = Bits::len_common_bits(&unit.bits, &bits);
+        let unit = left
+            .as_ref()
+            .ok_or(ContractError::MonotreeError("delete_key(): left-unit".to_string()))?;
+        let n = Bits::len_common_bits(&unit.bits, &bits)?;
 
         match n {
             // Found the exact key to delete
@@ -594,14 +609,14 @@ impl<D: MonotreeStorageAdapter> Monotree<D> {
         leaves: &[Hash],
     ) -> GenericResult<Option<Hash>> {
         let indices = get_sorted_indices(keys, false);
-        self.prepare();
+        self.prepare()?;
 
         let mut root = root.cloned();
         for i in indices.iter() {
             root = self.insert(root.as_ref(), &keys[*i], &leaves[*i])?;
         }
 
-        self.commit();
+        self.commit()?;
         Ok(root)
     }
 
@@ -619,13 +634,13 @@ impl<D: MonotreeStorageAdapter> Monotree<D> {
     pub fn removes(&mut self, root: Option<&Hash>, keys: &[Hash]) -> GenericResult<Option<Hash>> {
         let indices = get_sorted_indices(keys, false);
         let mut root = root.cloned();
-        self.prepare();
+        self.prepare()?;
 
         for i in indices.iter() {
             root = self.remove(root.as_ref(), &keys[*i])?;
         }
 
-        self.commit();
+        self.commit()?;
         Ok(root)
     }
 
@@ -648,10 +663,15 @@ impl<D: MonotreeStorageAdapter> Monotree<D> {
         bits: Bits,
         proof: &mut Proof,
     ) -> GenericResult<Option<Proof>> {
-        let bytes = self.db.get(root)?.expect("gen_proof(): bytes");
+        let bytes = self
+            .db
+            .get(root)?
+            .ok_or(ContractError::MonotreeError("gen_proof(): bytes".to_string()))?;
         let (cell, _) = Node::cells_from_bytes(&bytes, bits.first())?;
-        let unit = cell.as_ref().expect("gen_proof(): left-unit");
-        let n = Bits::len_common_bits(&unit.bits, &bits);
+        let unit = cell
+            .as_ref()
+            .ok_or(ContractError::MonotreeError("gen_proof(): left-unit".to_string()))?;
+        let n = Bits::len_common_bits(&unit.bits, &bits)?;
 
         match n {
             n if n == bits.len() => {
@@ -683,9 +703,13 @@ impl<D: MonotreeStorageAdapter> Monotree<D> {
 /// Verify a MerkleProof with the given root and leaf.
 ///
 /// NOTE: We use `Monotree::<MemoryDb>` to `hash_digest()` but it doesn't matter.
-pub fn verify_proof(root: Option<&Hash>, leaf: &Hash, proof: Option<&Proof>) -> bool {
+pub fn verify_proof(
+    root: Option<&Hash>,
+    leaf: &Hash,
+    proof: Option<&Proof>,
+) -> GenericResult<bool> {
     match proof {
-        None => false,
+        None => Ok(false),
         Some(proof) => {
             let mut hash = leaf.to_owned();
             proof.iter().rev().for_each(|(right, cut)| {
@@ -698,7 +722,9 @@ pub fn verify_proof(root: Option<&Hash>, leaf: &Hash, proof: Option<&Proof>) ->
                     hash = Monotree::<MemoryDb>::hash_digest(&o);
                 }
             });
-            root.expect("verify_proof(): root") == &hash
+
+            Ok(root.ok_or(ContractError::MonotreeError("verify_proof(): root".to_string()))? ==
+                &hash)
         }
     }
 }

+ 19 - 18
src/sdk/src/monotree/utils.rs

@@ -19,6 +19,7 @@
 
 use std::{cmp, ops::Range};
 
+use crate::{ContractError, GenericResult};
 use num::{NumCast, PrimInt};
 use rand::Rng;
 
@@ -39,8 +40,8 @@ macro_rules! min {
 }
 
 /// Cast from a typed scalar to another based on `num_traits`
-pub fn cast<T: NumCast, U: NumCast>(n: T) -> U {
-    NumCast::from(n).expect("cast(): Numcast")
+pub fn cast<T: NumCast, U: NumCast>(n: T) -> GenericResult<U> {
+    NumCast::from(n).ok_or(ContractError::NumCastError)
 }
 
 /// Generate a random byte based on `rand::random`.
@@ -97,12 +98,12 @@ where
 }
 
 /// Get length of the longest common prefix bits for the given two slices.
-pub fn len_lcp<T>(a: &[u8], m: &Range<T>, b: &[u8], n: &Range<T>) -> T
+pub fn len_lcp<T>(a: &[u8], m: &Range<T>, b: &[u8], n: &Range<T>) -> GenericResult<T>
 where
     T: PrimInt + NumCast,
     Range<T>: Iterator<Item = T>,
 {
-    let count = (cast(0)..min!(m.end - m.start, n.end - n.start))
+    let count = (cast(0)?..min!(m.end - m.start, n.end - n.start))
         .take_while(|&i| bit(a, m.start + i) == bit(b, n.start + i))
         .count();
     cast(count)
@@ -123,14 +124,14 @@ pub fn bit<T: PrimInt + NumCast>(bytes: &[u8], i: T) -> bool {
 }
 
 /// Get the required length of bytes from a `Range`, bits indices across the bytes.
-pub fn nbytes_across<T: PrimInt + NumCast>(start: T, end: T) -> T {
-    let eight = cast(8);
+pub fn nbytes_across<T: PrimInt + NumCast>(start: T, end: T) -> GenericResult<T> {
+    let eight = cast(8)?;
     let bits = end - (start - start % eight);
-    (bits + eight - T::one()) / eight
+    Ok((bits + eight - T::one()) / eight)
 }
 
 /// Convert big-endian bytes into base10 or decimal number.
-pub fn bytes_to_int<T: PrimInt + NumCast>(bytes: &[u8]) -> T {
+pub fn bytes_to_int<T: PrimInt + NumCast>(bytes: &[u8]) -> GenericResult<T> {
     let l = bytes.len();
     let sum = (0..l).fold(0, |sum, i| sum + (1 << ((l - i - 1) * 8)) * bytes[i] as usize);
     cast(sum)
@@ -182,16 +183,16 @@ mod tests {
 
     #[test]
     fn test_nbyte_across() {
-        assert_eq!(nbytes_across(0, 8), 1);
-        assert_eq!(nbytes_across(1, 7), 1);
-        assert_eq!(nbytes_across(5, 9), 2);
-        assert_eq!(nbytes_across(9, 16), 1);
-        assert_eq!(nbytes_across(7, 19), 3);
+        assert_eq!(nbytes_across(0, 8).unwrap(), 1);
+        assert_eq!(nbytes_across(1, 7).unwrap(), 1);
+        assert_eq!(nbytes_across(5, 9).unwrap(), 2);
+        assert_eq!(nbytes_across(9, 16).unwrap(), 1);
+        assert_eq!(nbytes_across(7, 19).unwrap(), 3);
     }
 
     #[test]
     fn test_bytes_to_int() {
-        let number: usize = bytes_to_int(&[0x73, 0x6f, 0x66, 0x69, 0x61]);
+        let number: usize = bytes_to_int(&[0x73, 0x6f, 0x66, 0x69, 0x61]).unwrap();
         assert_eq!(number, 495790221665usize);
     }
 
@@ -235,9 +236,9 @@ mod tests {
     fn test_len_lcp() {
         let sofia = [0x73, 0x6f, 0x66, 0x69, 0x61];
         let maria = [0x6d, 0x61, 0x72, 0x69, 0x61];
-        assert_eq!(len_lcp(&sofia, &(0..3), &maria, &(0..3)), 3);
-        assert_eq!(len_lcp(&sofia, &(0..3), &maria, &(5..9)), 0);
-        assert_eq!(len_lcp(&sofia, &(2..9), &maria, &(18..30)), 5);
-        assert_eq!(len_lcp(&sofia, &(20..30), &maria, &(3..15)), 4);
+        assert_eq!(len_lcp(&sofia, &(0..3), &maria, &(0..3)).unwrap(), 3);
+        assert_eq!(len_lcp(&sofia, &(0..3), &maria, &(5..9)).unwrap(), 0);
+        assert_eq!(len_lcp(&sofia, &(2..9), &maria, &(18..30)).unwrap(), 5);
+        assert_eq!(len_lcp(&sofia, &(20..30), &maria, &(3..15)).unwrap(), 4);
     }
 }