Skip to content

Commit

Permalink
feat(ic-asset-certification): add certification for individual chunks
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanosdev authored and przydatek committed Oct 25, 2024
1 parent 8f11afd commit dcbd7d4
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 29 deletions.
1 change: 1 addition & 0 deletions packages/ic-asset-certification/src/asset_router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ impl<'content> AssetRouter<'content> {
encoding,
Some(range_begin),
)?;
self.tree.borrow_mut().insert(&response.tree_entry);
self.responses.insert(
RequestKey::new(&asset_url, encoding_str(encoding), Some(range_begin)),
response,
Expand Down
27 changes: 10 additions & 17 deletions packages/ic-certification/src/hash_tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,22 +341,17 @@ impl<Storage: AsRef<[u8]>> fmt::Debug for HashTreeNode<Storage> {
// }
// ```
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn readable_print(f: &mut fmt::Formatter<'_>, v: &[u8]) -> fmt::Result {
fn readable_print(v: &[u8]) -> String {
// If it's UTF-8 and all the characters are graphic ASCII, then show as a string.
// If it's short, show hex.
// Otherwise, show length.
match std::str::from_utf8(v) {
Ok(s) if s.chars().all(|c| c.is_ascii_graphic()) => {
f.write_str("\"")?;
f.write_str(s)?;
f.write_str("\"")
}
Ok(s) if s.chars().all(|c| c.is_ascii_graphic()) => s.to_string(),
_ if v.len() <= 32 => {
f.write_str("0x")?;
f.write_str(&hex::encode(v))
format!("0x{}", hex::encode(v))
}
_ => {
write!(f, "{} bytes", v.len())
format!("{} bytes", v.len())
}
}
}
Expand All @@ -370,16 +365,14 @@ impl<Storage: AsRef<[u8]>> fmt::Debug for HashTreeNode<Storage> {
.finish(),
HashTreeNode::Leaf(v) => {
f.write_str("Leaf(")?;
readable_print(f, v.as_ref())?;
f.write_str(")")
}
HashTreeNode::Labeled(l, node) => {
f.write_str("Label(")?;
readable_print(f, l.as_bytes())?;
f.write_str(", ")?;
node.fmt(f)?;
f.write_str(&readable_print(v.as_ref()))?;
f.write_str(")")
}
HashTreeNode::Labeled(l, node) => f
.debug_tuple("Label")
.field(&readable_print(l.as_bytes()))
.field(&node)
.finish(),
HashTreeNode::Pruned(digest) => write!(f, "Pruned({})", hex::encode(digest.as_ref())),
}
}
Expand Down
35 changes: 33 additions & 2 deletions packages/ic-certification/src/nested_rb_tree.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::{empty, fork, labeled, leaf, pruned, AsHashTree, Hash, HashTree, HashTreeNode, RbTree};
use std::fmt::Debug;
use std::fmt::{Debug, Formatter};

pub trait NestedTreeKeyRequirements: Debug + Clone + AsRef<[u8]> + 'static {}
pub trait NestedTreeValueRequirements: Debug + Clone + AsHashTree + 'static {}
impl<T> NestedTreeKeyRequirements for T where T: Debug + Clone + AsRef<[u8]> + 'static {}
impl<T> NestedTreeValueRequirements for T where T: Debug + Clone + AsHashTree + 'static {}

#[derive(Debug, Clone)]
#[derive(Clone)]
pub enum NestedTree<K: NestedTreeKeyRequirements, V: NestedTreeValueRequirements> {
Leaf(V),
Nested(RbTree<K, NestedTree<K, V>>),
Expand All @@ -18,6 +18,18 @@ impl<K: NestedTreeKeyRequirements, V: NestedTreeValueRequirements> Default for N
}
}

impl<K: NestedTreeKeyRequirements, V: NestedTreeValueRequirements> Debug for NestedTree<K, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let s = match &self {
NestedTree::Leaf(leaf) => {
format!("NestedTree::Leaf({})", hex::encode(leaf.root_hash()))
}
NestedTree::Nested(rb_tree) => format!("NestedTree({:#?})", rb_tree),
};
write!(f, "{}", s)
}
}

impl<K: NestedTreeKeyRequirements, V: NestedTreeValueRequirements> AsHashTree for NestedTree<K, V> {
fn root_hash(&self) -> Hash {
match self {
Expand Down Expand Up @@ -445,6 +457,25 @@ mod tests {
merge_hash_trees(lhs, rhs);
}

#[test]
fn should_display_labels_and_hex_hashes() {
let label_1 = "label 1";
let label_2 = "label 2";

let value_1 = [1, 2, 3, 4, 5];
let value_2 = [7, 8, 9, 10];

let mut tree: NestedTree<&str, Vec<u8>> = NestedTree::default();
tree.insert(&[label_1, label_2], value_1.to_vec());
tree.insert(&[label_2, label_1], value_2.to_vec());

let s = format!("{:?}", tree);
assert!(s.contains(label_1));
assert!(s.contains(label_2));
assert!(s.contains(&format!("0x{}", hex::encode(value_1))));
assert!(s.contains(&format!("0x{}", hex::encode(value_2))));
}

#[fixture]
fn pruned_a() -> HashTree {
pruned(Hash::from([0u8; 32]))
Expand Down
17 changes: 8 additions & 9 deletions packages/ic-certification/src/rb_tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use crate::{
hash_tree::{fork, fork_hash, labeled_hash, leaf_hash, Hash},
labeled, leaf, pruned, HashTree, HashTreeNode,
};
use std::borrow::Cow;
use std::cmp::Ordering::{self, Equal, Greater, Less};
use std::{borrow::Cow, fmt::Debug};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Color {
Expand Down Expand Up @@ -331,16 +331,15 @@ where
V: 'static + AsHashTree + std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[")?;
let mut first = true;
let mut list = f.debug_list();
for (k, v) in self.iter() {
if !first {
write!(f, ", ")?;
}
first = false;
write!(f, "({:?}, {:?})", k, v)?;
list.entry(&format_args!(
"({}, {:#?})",
String::from_utf8_lossy(k.as_ref()),
v.as_hash_tree()
));
}
write!(f, "]")
list.finish()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,22 @@ use crate::{
};
use ic_certification::{labeled, labeled_hash, merge_hash_trees, AsHashTree, HashTree, NestedTree};
use ic_representation_independent_hash::Sha256Digest;
use std::fmt::{Debug, Formatter};

type CertificationTree = NestedTree<CertificationTreePathSegment, Vec<u8>>;

/// A certification tree for generic HTTP requests.
#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct HttpCertificationTree {
tree: CertificationTree,
}

impl Debug for HttpCertificationTree {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "tree: {:#?}", self.tree)
}
}

impl Default for HttpCertificationTree {
fn default() -> Self {
Self::new(CertificationTree::default())
Expand Down

0 comments on commit dcbd7d4

Please sign in to comment.