From 2cbe7160b6c4ca2bebc5fec753ca23e2a12b07b2 Mon Sep 17 00:00:00 2001 From: qima Date: Thu, 29 Aug 2024 00:29:20 +0800 Subject: [PATCH] feat(register): logging update history --- sn_client/src/register.rs | 2 +- sn_node/tests/storage_payments.rs | 6 +++ sn_registers/src/register.rs | 80 ++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 3 deletions(-) diff --git a/sn_client/src/register.rs b/sn_client/src/register.rs index 3361006139..a19674aca4 100644 --- a/sn_client/src/register.rs +++ b/sn_client/src/register.rs @@ -32,7 +32,7 @@ use xor_name::XorName; pub struct ClientRegister { #[debug(skip)] client: Client, - pub(crate) register: Register, + pub register: Register, pub ops: LinkedList, // Cached operations. } diff --git a/sn_node/tests/storage_payments.rs b/sn_node/tests/storage_payments.rs index f9814ef336..57e63f05b6 100644 --- a/sn_node/tests/storage_payments.rs +++ b/sn_node/tests/storage_payments.rs @@ -331,6 +331,12 @@ async fn storage_payment_register_creation_succeeds() -> Result<()> { assert_eq!(retrieved_reg.read().iter().next().unwrap().1, random_entry); + println!("Current fetched register is {:?}", retrieved_reg.register); + println!( + "Fetched register has update history of {}", + retrieved_reg.register.log_update_history() + ); + std::thread::sleep(std::time::Duration::from_millis(1000)); } diff --git a/sn_registers/src/register.rs b/sn_registers/src/register.rs index 23fd154ea5..55059be50b 100644 --- a/sn_registers/src/register.rs +++ b/sn_registers/src/register.rs @@ -12,9 +12,9 @@ use crate::{ }; use bls::{PublicKey, SecretKey, Signature}; -use crdts::merkle_reg::MerkleReg; +use crdts::merkle_reg::{Hash, MerkleReg}; use serde::{Deserialize, Serialize}; -use std::collections::BTreeSet; +use std::collections::{BTreeSet, HashSet}; use xor_name::XorName; /// Arbitrary maximum size of a register entry. @@ -262,6 +262,82 @@ impl Register { self.crdt.merkle_reg() } + /// Log the structure of the MerkleReg within this Register's CRDT as a tree view. + /// This is actually being the `update history` of the register. + pub fn log_update_history(&self) -> String { + let mut output = "MerkleReg Structure:\n".to_string(); + let merkle_reg = self.crdt.merkle_reg(); + output = format!( + "{output}Total entries: {}\n", + merkle_reg.num_nodes() + merkle_reg.num_orphans() + ); + + // Find root nodes (entries with no parents) + let roots: Vec<_> = merkle_reg.read().hashes().into_iter().collect(); + + // Print the tree starting from each root + for (i, root) in roots.iter().enumerate() { + let mut visited = HashSet::new(); + Self::print_tree( + root, + merkle_reg, + &mut output, + "", + i == roots.len() - 1, + &mut visited, + ); + } + + output + } + + // Helper function to recursively print the MerkleReg tree + fn print_tree( + hash: &Hash, + merkle_reg: &MerkleReg, + output: &mut String, + prefix: &str, + is_last: bool, + visited: &mut HashSet, + ) { + let pretty_hash = format!("{}", XorName::from_content(hash)); + if !visited.insert(*hash) { + *output = format!( + "{}{prefix}{}* {pretty_hash} (cycle detected)\n", + output, + if is_last { "└── " } else { "├── " }, + ); + return; + } + + let entry = if let Some(node) = merkle_reg.node(*hash) { + format!("value: {}", XorName::from_content(&node.value)) + } else { + "value: None".to_string() + }; + *output = format!( + "{}{prefix}{}{pretty_hash}: {entry}\n", + output, + if is_last { "└── " } else { "├── " }, + ); + + let children: Vec<_> = merkle_reg.children(*hash).hashes().into_iter().collect(); + let new_prefix = format!("{prefix}{} ", if is_last { " " } else { "│" }); + + for (i, child) in children.iter().enumerate() { + Self::print_tree( + child, + merkle_reg, + output, + &new_prefix, + i == children.len() - 1, + visited, + ); + } + + visited.remove(hash); + } + // Private helper to check the given Entry's size is within define limit, // as well as check the Register hasn't already reached the maximum number of entries. fn check_entry_and_reg_sizes(&self, entry: &Entry) -> Result<()> {