p2p、分布式,区块链笔记: Merkle-DAG和Merkle-Tree的区别与联系

Merkle-DAG和Merkle-Tree的区别与联系

  1. 结构:

  2. 用途:

    • Merkle-Tree 通常用于区块链和文件系统中以验证数据块的完整性(如 Bitcoin 和 Git)。
    • Merkle-DAG 用于数据去重和版本控制(如 IPFS),支持更灵活的数据组织和高效的同步。

CODE

NODE结构体

  • node.rs中定义了一个在Merkle DAG(有向无环图)中使用的节点结构体(Node)。每个节点包含一个有效载荷(item)和一组依赖ID(dependency_ids)。节点的唯一标识符(id)是由有效载荷和依赖ID的字节组合而成,确保相同的有效载荷和依赖ID总是有相同的ID。

    // 代码位置 https://github1s.com/zaphar/merkle-dag/blob/main/src/node.rs#L51-L62
    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
    #[serde(from = "NodeSerde")]
    pub struct Node<HW> // <HW> 为泛型参数
    where
    HW: HashWriter, // where为泛型约束,泛型参数 HW 必须实现 HashWriter trait
    {
    id: Vec<u8>,
    item: Vec<u8>,
    item_id: Vec<u8>,
    dependency_ids: BTreeSet<Vec<u8>>,
    _phantom: PhantomData<HW>,
    }

add_node函数

函数签名

rust 复制代码
pub fn add_node<'a, N: Into<Vec<u8>>>(
    &'a mut self,
    item: N,
    dependency_ids: BTreeSet<Vec<u8>>,
) -> Result<Vec<u8>>
  • 'a : 生命周期标注,表明函数借用的是 self 的生命周期。
  • N: Into<Vec<u8>> : 泛型参数 N,它可以转换为 Vec<u8>
  • item : 节点的负载数据,将被转换为 Vec<u8>
  • dependency_ids : 节点的依赖 ID 集合,每个 ID 是 Vec<u8> 类型。
  • Result<Vec<u8>>: 函数返回一个结果,如果成功,返回新节点的 ID;如果失败,返回错误。

函数解释

  • add_node 函数负责将一个带有依赖关系的新节点添加到 Merkle-DAG 中。它首先检查节点是否已经存在,处理依赖关系,并更新节点存储和根集合。该函数确保节点的添加操作是幂等的,即对于相同的输入,结果不会发生变化。
复制代码
/// 添加一个新负载及其依赖 ID 集合。此方法将构建一个新节点,并将其添加到 DAG 中。
/// 对于任何给定的输入,该方法是幂等的。
///
/// 不创建节点然后再添加的一个结果是,确保始终满足 merkle-crdt 白皮书中的实现规则。
pub fn add_node<'a, N: Into<Vec<u8>>>(
    &'a mut self,
    item: N,
    dependency_ids: BTreeSet<Vec<u8>>,
) -> Result<Vec<u8>> {
    // 使用提供的负载和依赖 ID 创建一个新节点实例。
    let node = Node::<HW>::new(item.into(), dependency_ids.clone());
    // 获取新创建的节点的 ID。
    let id = node.id().to_vec();
    
    // 检查节点是否已经存在于存储中。
    if self.nodes.contains(id.as_slice())? {
        // 如果节点已存在,则返回该节点的 ID。
        return Ok(self
            .nodes
            .get(id.as_slice())
            .unwrap()
            .unwrap()
            .id()
            .to_vec());
    }
    
    // 初始化一个向量,用于记录需要从根集合中移除的节点。
    let mut root_removals = Vec::new();
    
    // 遍历所有的依赖 ID。
    for dep_id in dependency_ids.iter() {
        // 检查每个依赖节点是否存在于存储中。
        if !self.nodes.contains(dep_id)? {
            // 如果任何依赖节点不存在,则返回错误。
            return Err(StoreError::NoSuchDependents);
        }
        // 如果某个依赖 ID 存在于根集合中,则将其标记为需要移除。
        if self.roots.contains(dep_id) {
            root_removals.push(dep_id);
        }
    }
    
    // 更新根集合
    // 将新节点存储到节点存储中。
    self.nodes.store(node)?; // https://github1s.com/zaphar/merkle-dag/blob/main/src/store.rs
    
    // 从根集合中移除被标记的节点。
    for removal in root_removals {
        self.roots.remove(removal);
    }
    
    // 将新节点的 ID 添加到根集合中。
    self.roots.insert(id.to_vec());
    
    // 返回新节点的 ID。
    Ok(id.to_vec())
}

函数调用

  1. TestDag别名类型:

    rust 复制代码
    // https://github1s.com/zaphar/merkle-dag/blob/main/src/test.rs#L19-L22
    type TestDag<'a> = Merkle<
        BTreeMap<Vec<u8>, Node<std::collections::hash_map::DefaultHasher>>,
        std::collections::hash_map::DefaultHasher,
    >;
    • Merkle 的第一个泛型参数是 BTreeMap<Vec<u8>, Node<std::collections::hash_map::DefaultHasher>>,它是一个键为 Vec<u8>,值为 Node<DefaultHasher> 的映射。
    • 第二个泛型参数是 DefaultHasher,它是一个标准库提供的哈希算法。
  2. 测试函数:

    rust 复制代码
    // https://github1s.com/zaphar/merkle-dag/blob/main/src/test.rs#L26-L27
    #[test]
    fn test_root_pointer_hygiene() {
        let mut dag = TestDag::new(BTreeMap::new());
        let quax_node_id = dag.add_node("quax", BTreeSet::new()).unwrap();
    }
    • #[test] 属性标记此函数为测试函数。
    • dag 通过 TestDag::new(BTreeMap::new()) 创建一个新的 TestDag 实例,传入一个空的 BTreeMap
    • quax_node_id 调用 dag.add_node("quax", BTreeSet::new()) 方法添加一个新节点,节点 ID 被赋值给 quax_node_idunwrap() 处理可能出现的错误,确保成功添加节点。

CG

相关推荐
幼稚园的山代王37 分钟前
RabbitMQ 4.1.1初体验-队列和交换机
分布式·rabbitmq·ruby
HuashuiMu花水木39 分钟前
PyTorch笔记1----------Tensor(张量):基本概念、创建、属性、算数运算
人工智能·pytorch·笔记
小新学习屋1 小时前
Spark从入门到熟悉(篇三)
大数据·分布式·spark
笑衬人心。3 小时前
Ubuntu 22.04 修改默认 Python 版本为 Python3 笔记
笔记·python·ubuntu
金色光环4 小时前
【Modbus学习笔记】stm32实现Modbus
笔记·stm32·学习
沉着的码农5 小时前
【设计模式】基于责任链模式的参数校验
java·spring boot·分布式
zyxzyx6665 小时前
Flyway 介绍以及与 Spring Boot 集成指南
spring boot·笔记
西岭千秋雪_6 小时前
Redis性能优化
数据库·redis·笔记·学习·缓存·性能优化
HuashuiMu花水木7 小时前
Matplotlib笔记4----------图像处理
图像处理·笔记·matplotlib
DES 仿真实践家8 小时前
【Day 11-N22】Python类(3)——Python的继承性、多继承、方法重写
开发语言·笔记·python