From dcbd7d471e1a5f95d8b1e8a66c4a35fd2a68268f Mon Sep 17 00:00:00 2001 From: NathanosDev Date: Thu, 24 Oct 2024 23:09:26 +0200 Subject: [PATCH] feat(ic-asset-certification): add certification for individual chunks --- .../src/asset_router.rs | 1 + .../ic-certification/src/hash_tree/mod.rs | 27 ++++++-------- .../ic-certification/src/nested_rb_tree.rs | 35 +++++++++++++++++-- packages/ic-certification/src/rb_tree/mod.rs | 17 +++++---- .../src/tree/certification_tree.rs | 9 ++++- 5 files changed, 60 insertions(+), 29 deletions(-) diff --git a/packages/ic-asset-certification/src/asset_router.rs b/packages/ic-asset-certification/src/asset_router.rs index 53793e05..e04320b8 100644 --- a/packages/ic-asset-certification/src/asset_router.rs +++ b/packages/ic-asset-certification/src/asset_router.rs @@ -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, diff --git a/packages/ic-certification/src/hash_tree/mod.rs b/packages/ic-certification/src/hash_tree/mod.rs index 21be2675..efb8d414 100644 --- a/packages/ic-certification/src/hash_tree/mod.rs +++ b/packages/ic-certification/src/hash_tree/mod.rs @@ -341,22 +341,17 @@ impl> fmt::Debug for HashTreeNode { // } // ``` 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()) } } } @@ -370,16 +365,14 @@ impl> fmt::Debug for HashTreeNode { .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())), } } diff --git a/packages/ic-certification/src/nested_rb_tree.rs b/packages/ic-certification/src/nested_rb_tree.rs index a5502865..5ed32353 100644 --- a/packages/ic-certification/src/nested_rb_tree.rs +++ b/packages/ic-certification/src/nested_rb_tree.rs @@ -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 NestedTreeKeyRequirements for T where T: Debug + Clone + AsRef<[u8]> + 'static {} impl NestedTreeValueRequirements for T where T: Debug + Clone + AsHashTree + 'static {} -#[derive(Debug, Clone)] +#[derive(Clone)] pub enum NestedTree { Leaf(V), Nested(RbTree>), @@ -18,6 +18,18 @@ impl Default for N } } +impl Debug for NestedTree { + 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 AsHashTree for NestedTree { fn root_hash(&self) -> Hash { match self { @@ -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> = 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])) diff --git a/packages/ic-certification/src/rb_tree/mod.rs b/packages/ic-certification/src/rb_tree/mod.rs index ede6f71c..8226be58 100644 --- a/packages/ic-certification/src/rb_tree/mod.rs +++ b/packages/ic-certification/src/rb_tree/mod.rs @@ -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 { @@ -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() } } diff --git a/packages/ic-http-certification/src/tree/certification_tree.rs b/packages/ic-http-certification/src/tree/certification_tree.rs index 0960efd6..f4b80d79 100644 --- a/packages/ic-http-certification/src/tree/certification_tree.rs +++ b/packages/ic-http-certification/src/tree/certification_tree.rs @@ -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>; /// 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())