【大白话解析】 OpenZeppelin 的 MerkleProof 库:Solidity 默克尔证明验证工具全指南​​(附源代码)

🧩 一、Merkle Tree 是什么?为什么要验证它?

想象你有一个名单,比如:

["Alice", "Bob", "Charlie", "Dave"]

你想让别人验证:“我(比如 Alice)是不是在这个名单里?”,但不想把整个名单都放在区块链上(太贵!)。

于是你用一种数据结构 —— ​​Merkle Tree(默克尔树)​​,把所有名字(或它们的哈希)组织成一棵树,最终得到一个唯一的“总照片”叫 ​​Merkle Root(根哈希)​​,你把这个根哈希存在区块链上。

别人(比如 Alice)给你:

  • 她自己的名字的哈希(leaf)

  • 从她到根路径上的一些“邻居哈希”(proof)

  • 一组“怎么拼”的规则(proofFlags,或者按顺序)

  • 你就能用这些信息,​​在链上计算出根哈希,看是否和你存证的一样​​,如果一样,说明她在名单里 ✅


🏗️ 二、这个库(MerkleProof.sol)是干嘛的?

这是一个 ​​工具库(Library)​​,提供了一系列函数,用来:

  • 验证 ​​单个数据​​ 是否属于某个 Merkle Tree

  • 验证 ​​多个数据(批量)​​ 是否同属于某个 Merkle Tree

  • 支持 ​​不同存储方式(memory / calldata)​

  • 支持 ​​默认 Keccak256 哈希 或 自定义哈希函数​

它封装了所有和 Merkle Proof(默克尔证明)验证相关的核心逻辑,让开发者可以很方便地集成到自己的 DApp / 合约中。


📦 三、文件结构 & 导入说明

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;import {Hashes} from "./Hashes.sol";
  • 使用 ​​Solidity 0.8.20​

  • 引入了一个工具库 Hashes.sol,它提供了一个关键函数:

    commutativeKeccak256(a, b)→ 这是一个 ​​可交换顺序的 Keccak256 哈希函数​​,即 hash(a,b) == hash(b,a),这在构建 Merkle Tree 时非常有用,因为父子节点的左右顺序有时不重要。


❗ 四、自定义错误

error MerkleProofInvalidMultiproof();
  • 当你传入的 ​​证明数据(proof)和叶子数据(leaves)不匹配​​(数量不对,结构不合理)时,就会报这个错,防止无效验证。


✅ 五、核心功能分类

这个库主要提供两类验证:

  1. ​单个数据验证(verify / processProof)​

  2. ​多个数据同时验证(multiProofVerify / processMultiProof)​

并且每种都支持:

  • ​普通版本(memory 存储)​

  • ​高效版本(calldata 存储,省 gas)​

  • ​默认 Keccak256 哈希​

  • ​自定义哈希函数​

我们逐一来看 👇


🟢 1. 单个数据验证(memory版)

🔹 函数:verify(proof, root, leaf)

 /*** @dev 验证单个叶子是否属于默克尔树* @param proof 证明路径数组,包含从叶子到根的所有兄弟哈希* @param root 默克尔树的根哈希* @param leaf 待验证的叶子哈希* @return 如果验证成功返回true,否则返回false* * 示例:* 假设默克尔树有4个叶子:A、B、C、D* 验证C是否在树中:* bytes32[] memory proof = [D的哈希, (A+B)的哈希];* bool isValid = MerkleProof.verify(proof, rootHash, hash(C));*/function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {// 处理证明并与根哈希比较return processProof(proof, leaf) == root;}
  • ​作用​​:验证一个 leaf(比如你的地址哈希)是否属于某个 Merkle Tree(通过 root 和 proof)

  • ​参数​​:

    • proof: 从该叶子到根路径上的 “兄弟节点哈希” 数组

    • root: Merkle Tree 的根哈希(存在链上的那个)

    • leaf: 你要验证的叶子哈希(比如 keccak256(你的地址))

  • ​返回​​:true/false,是否验证通过

🔍 ​​它是怎么做的?​

  • 调用了 processProof(proof, leaf),这个函数会:

    • 从你的叶子开始

    • 依次和 proof 里的“兄弟哈希”做哈希组合(一层一层往上爬)

    • 最终得到一个哈希,就是这棵树的根

  • 然后判断这个计算出来的根,是否等于传入的 root,一样就 ✅

🔹 函数:processProof(proof, leaf)

/*** @dev 处理证明路径,从叶子计算出根哈希* * 【实际区块链场景】:* 比如你参与了一个 Token 空投,项目方用 Merkle Tree 管理所有空投用户,* 你拿到:* - 你的叶子:你的钱包地址的哈希(比如 0x1111...)* - 一个证明路径(proof):包含你从叶子到根过程中,每一层的“隔壁节点哈希”(兄弟节点)* - 你调用这个函数,传入你的叶子 + 证明路径,它就会帮你算出整棵树的根哈希* - 然后你拿这个根去和项目方存在链上的根对比,如果一样,你就能领空投啦!✅* * @param proof 证明路径数组*    这是一个数组,里面装的是你在从叶子到根的过程中,每一层需要用到的“兄弟节点哈希”*    比如:[0x2222..., 0x3333..., 0x4444...],它们是你路径上的“邻居”* * @param leaf 待验证的叶子哈希*    这是你自己的数据哈希,比如你的钱包地址经过 keccak256 后的值:0x1111...* * @return 计算得到的根哈希*    最终拼出来的 Merkle 树的根,用来和链上存证的根做对比*/function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {// 🌱 初始化:我们从叶子节点开始,这就是你自己的数据哈希bytes32 computedHash = leaf;// 比如:computedHash = 0x1111111111111111111111111111111111111111(你的地址哈希)// 🔁 遍历证明路径中的每一个兄弟节点哈希,逐步向上计算父节点哈希for (uint256 i = 0; i < proof.length; i++) {// 🧩 每次循环,你都会拿到一个“兄弟节点哈希”:proof[i]// 比如第1次循环:proof[0] = 0x2222...,第2次:proof[1] = 0x3333...,依此类推// 🔐 使用一个“可交换的哈希函数”来合并:computedHash(你的节点)和 proof[i](兄弟节点)// 这里调用了 Hashes.commutativeKeccak256(...),它本质上就是 keccak256(abi.encodePacked(a, b))// 但“可交换”意味着你先传 a 还是 b 都没关系,结果是一样的(keccak 本身是可交换的,只要顺序一致)computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);// 【例子】:// 第1次循环:computedHash = keccak256(0x1111..., 0x2222...) → 假设结果是 0x1234...// 第2次循环:computedHash = keccak256(0x1234..., 0x3333...) → 假设结果是 0x5678...// 第3次循环:computedHash = keccak256(0x5678..., 0x4444...) → 假设最终根是 0xAAAA...}// 🎯 最终返回:经过所有证明路径节点合并后,得到的根哈希return computedHash;// 比如最终返回:0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(Merkle 树的根)}
  • 内部实现:就是不断地把你的 leaf 和 proof 里的哈希两两组合(用commutativeKeccak256),最终返回根哈希


🟢 2. 单个数据验证(memory版,带自定义哈希函数)

/*** @dev 带自定义哈希函数的单个叶子验证* @param proof 证明路径数组* @param root 默克尔树的根哈希* @param leaf 待验证的叶子哈希* @param hasher 自定义哈希函数* @return 验证结果* * 示例:* 使用SHA256作为哈希函数(需提前实现)* bool isValid = MerkleProof.verify(proof, rootHash, hash(C), sha256Hash);*/function verify(bytes32[] memory proof,bytes32 root,bytes32 leaf,function(bytes32, bytes32) view returns (bytes32) hasher) internal view returns (bool) {return processProof(proof, leaf, hasher) == root;}

这个功能是基于之前提到的:

​1. 单个数据验证(memory版)​

的 ​​升级版​​,区别在于:

  • 之前用的哈希函数是 ​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/94285.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94285.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机械学习综合练习项目

数据集合完整项目文件已经上传一、项目介绍案例介绍 案例是针对“红酒.csv”数据集&#xff0c;在红葡萄酒质量分析的场景 中&#xff0c;利用多元线性回归来探索红葡萄酒的不同化学成分如何共同 影响其质量评分。在建立线性回归模型之后&#xff0c;当给出了红葡萄酒 的新的一…

第3篇:配置管理的艺术 - 让框架更灵活

前言 在前一章中&#xff0c;我们设计了强大的注解API。本章将深入探讨配置管理系统的设计&#xff0c;学习如何将注解中的声明式配置转换为运行时可用的配置对象。 配置管理的核心挑战 在我们的框架中&#xff0c;配置来源有三个层级&#xff1a;主要挑战&#xff1a; &#x…

发版混乱怎么规范

你是否经历过这种场景&#xff1a;临到发版&#xff0c;一堆功能代码挤在一起&#xff0c;测试分不清范围&#xff0c;修复一个Bug可能引发三个新Bug&#xff1f;发布过程像一场豪赌&#xff1f;问题的核心往往在于分支策略和流程的混乱。今天&#xff0c;我们就来建立一套在绝…

【golang长途旅行第30站】channel管道------解决线程竞争的好手

channel 为什么需要channel 使用全局变量加锁同步来解决goroutine的竞争&#xff0c;可以但不完美难以精确控制等待时间​&#xff08;主线程无法准确知道所有 goroutine 何时完成&#xff09;。全局变量容易引发竞态条件​&#xff08;即使加锁&#xff0c;代码复杂度也会增加…

苹果XR芯片介绍

苹果的 XR 芯片技术主要体现在 A 系列、M 系列处理器以及专为空间计算设计的 R1 协处理器中。以下从技术架构、产品迭代和综合对比三个维度展开分析&#xff1a;一、技术架构解析1. A 系列芯片&#xff08;以 A12 Bionic 为例&#xff09;制程工艺&#xff1a;7nm&#xff08;台…

达梦数据库巡检常用SQL(三)

达梦数据库巡检常用SQL(三) 数据库SQL运行检查 数据库SQL运行检查 死锁的事务情况: SELECT TO_CHAR(HAPPEN_TIME,YYYY-MM-DD HH24:MI:SS) HAPPEN_TIME,SQL_TEXT FROM V$DEADLOCK_HISTORY WHERE HAPPEN_TIME >DATEADD(DAY,-30,

基于SpringBoot的校园周边美食探索及分享平台

1. 项目简介 项目名称&#xff1a;校园周边美食探索及分享平台 项目背景&#xff1a;针对校园师生对周边美食信息的需求&#xff0c;构建一个集美食推荐、鉴赏、评论互动及社交功能于一体的平台&#xff0c;帮助用户发现优质美食资源并进行分享交流。 主要目标&#xff1a; 提供…

Go数据结构与算法-常见的排序算法

虽然看过别人写了很多遍&#xff0c;而且自己也写过很多遍&#xff08;指的是笔记&#xff09;&#xff0c;但是还是要写的就是排序算法。毕竟是初学Go语言&#xff0c;虽然之前写过&#xff0c;但是还是打算再写一遍。主要包括插入排序、选择排序、冒泡排序、快速排序、堆排序…

第 6 篇:目标规则与负载均衡 - `DestinationRule` 详解

系列文章:《Istio 服务网格详解》 第 6 篇:目标规则与负载均衡 - DestinationRule 详解 本篇焦点: 深入理解 DestinationRule 的核心作用:定义流量在到达目的地之后的行为。 详细剖析其三大核心功能:服务子集 (Subsets), 流量策略 (Traffic Policy), TLS 设置。 动手实战…

一个简洁的 C++ 日志模块实现

一个简洁的 C 日志模块实现 1. 引言 日志功能在软件开发中扮演着至关重要的角色&#xff0c;它帮助开发者追踪程序执行过程、诊断问题以及监控系统运行状态。本文介绍一个使用 C 实现的轻量级日志模块&#xff0c;该模块支持多日志级别、线程安全&#xff0c;并提供了简洁易用…

C语言---数据类型

文章目录数据类型分类1. 基本类型 (Basic Types)a. 整数类型 (Integer Types)char (字符型)int (整型)short (短整型)long (长整型)long long (C99标准引入)图片汇总b. 浮点类型 (Floating-Point Types)float (单精度浮点型)double (双精度浮点型)long double (长双精度浮点型)…

本搭建乌云漏洞库

1.下载镜像站文件&#xff0c;并拖入虚拟机 2.将bugs.rar解压至网站根目录下 /var/www/html 3.配置bugs/conn.php 4.在bugs下创建upload目录&#xff0c;将10-14、15-a、15-b、16压缩包文件解压到该upload目录 5.把wooyun.rar解压到 /mysql/data/wooyun目录下 6.配置hosts文件后…

Vmware虚拟机 处理器配置选项配置介绍

1. 处理器配置选项好&#x1f44c;&#xff0c;我来帮你逐一解读 VMware 里 虚拟机处理器 这些选项的含义。 你截的图里&#xff0c;主要有三块内容&#xff1a; 处理器数量 每个处理器的内核数量 ©虚拟化引擎1️⃣ 处理器数量 这是分配给虚拟机的 逻辑 CPU 插槽数。一般…

day40-tomcat

1.每日复盘与今日内容1.1复盘keepalived高可用配置抢占式与非抢占式脑裂keepalived处理Nginx挂掉1.2今日内容部署、安装、配置tomcat(systemctl)Tomcat主配置文件部署静态页部署zrlog&#x1f35f;&#x1f35f;&#x1f35f;&#x1f35f;&#x1f35f;接入负载均衡挂载到NFS2…

【RA-Eco-RA4E2-64PIN-V1.0 开发板】步进电机的串口控制

【RA-Eco-RA4E2-64PIN-V1.0 开发板】步进电机的串口控制 本文介绍了 RA-Eco-RA4E2-64PIN-V1.0 开发板通过串口指令实现 28BYJ-48 步进电机旋转角度和速度的精确控制的项目设计。 项目介绍 硬件连接&#xff1a;28BYJ-48 步进电机、ULN2003 驱动板、Jlink 调试器、供电电源等&am…

PiscCode基于 Mediapipe 的人体多模态关键点检测与可视化系统 —— HumanMultiLandmarker 深度解析

一、引言 在计算机视觉领域&#xff0c;人体关键点检测&#xff08;Human Pose Estimation&#xff0c;HPE&#xff09;一直是研究和应用的热点方向之一。随着深度学习与实时图像处理技术的发展&#xff0c;人体姿势估计已经从传统的 2D 检测走向了 3D 空间建模&#xff0c;并…

文献阅读笔记【物理信息机器学习】:Physics-informed machine learning

文献阅读笔记&#xff1a;Physics-informed machine learningSummaryResearch ObjectiveBackground / Problem Statement问题背景研究现状需解决的问题问题出现的原因分析问题解决思路Method(s)问题建模作者解决问题的方法/算法1. 观测偏差&#xff08;Observational Biases&am…

Linux服务环境搭建指南

实验拓扑概述**实验拓扑&#xff1a; APPSRV&#xff1a; 主机名&#xff1a;appsrv.example.com ip地址&#xff1a;192.168.100.10 网关&#xff1a;192.168.100.254 网卡为NAT模式 STORAGESRV&#xff1a; 主机名&#xff1a;storagesrv.example.com ip地址&#xff1a;192.…

[特殊字符] 数据库知识点总结(SQL Server 方向)

一、数据库基础概念数据库&#xff08;Database&#xff09;&#xff1a;存储和管理数据的容器。数据表&#xff08;Table&#xff09;&#xff1a;以行和列形式组织数据。行&#xff08;Row&#xff09;&#xff1a;一条记录。列&#xff08;Column&#xff09;&#xff1a;字…

【PSINS工具箱】MATLAB例程,二维平面上的组合导航,EKF融合速度、位置和IMU数据,4维观测量

文章目录关于工具箱程序简介代码概述核心功能与步骤运行结果MATLAB代码关于工具箱 本文所述的代码需要基于PSINS工具箱&#xff0c;工具箱的讲解&#xff1a; PSINS初学指导&#xff1a;https://blog.csdn.net/callmeup/article/details/137087932 本文为二维平面上的定位&am…