Skip to content

Commit

Permalink
Implement range proofs
Browse files Browse the repository at this point in the history
  • Loading branch information
rkuris committed Nov 14, 2023
1 parent a08d9b2 commit c60eb8b
Showing 1 changed file with 56 additions and 4 deletions.
60 changes: 56 additions & 4 deletions firewood/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::{
use async_trait::async_trait;
use bytemuck::{cast_slice, AnyBitPattern};

use futures::{future::ready, StreamExt as _, TryStreamExt as _};
use metered::metered;
use parking_lot::{Mutex, RwLock};
use std::{
Expand Down Expand Up @@ -307,11 +308,62 @@ impl<S: ShaleStore<Node> + Send + Sync> api::DbView for DbRev<S> {

async fn range_proof<K: api::KeyType, V>(
&self,
_first_key: Option<K>,
_last_key: Option<K>,
_limit: Option<usize>,
first_key: Option<K>,
last_key: Option<K>,
limit: Option<usize>,
) -> Result<Option<api::RangeProof<Vec<u8>, Vec<u8>>>, api::Error> {
todo!()
let mut stream = self.stream(first_key.as_ref())?;

// fetch the first key from the stream
let first_result = stream.next().await;

// transpose the Option<Result<T, E>> to Result<Option<T>, E>
// If this is an error, the ? operator will return it
let Some((key, _)) = first_result.transpose()? else {
// nothing returned, either the trie is empty or the key wasn't found
return Ok(None);
};

let Some(first_key) = self.single_key_proof(key).await? else {
return Ok(None);
};

// we stop streaming if either we hit the limit or the key returned was larger
// than the largest key requested
let mut middle = stream
.take(limit.unwrap_or(usize::MAX))
.take_while(|kv_result| {
// no last key asked for, so keep going
let Some(last_key) = last_key.as_ref() else {
return ready(true);
};

// return the error if there was one
let Ok(kv) = kv_result else {
return ready(true);
};

// keep going if the key returned is less than the last key requested
ready(kv.0.as_slice() <= last_key.as_ref())
})
.try_collect::<Vec<(Vec<u8>, Vec<u8>)>>()
.await?;

// remove the last key from middle and do a proof on it
let last_key = match middle.pop() {
None => return Err(api::Error::RangeProofError("Range too small".to_owned())),
Some((last_key, _)) => self.single_key_proof(last_key).await,
};

let Ok(Some(last_key)) = last_key else {
return Ok(None);
};

Ok(Some(api::RangeProof {
first_key,
middle,
last_key,
}))
}
}

Expand Down

0 comments on commit c60eb8b

Please sign in to comment.