Solidity中哈希函数的编码与解码

news2024/11/15 14:08:42

起因

写这篇文章的起因,是我在前端调试合约的时候,发现合约报错了,点开命令行报错,发现返回的是合约的 callData,我直接表演一个眼前一黑,我怎么直接的知道是调用哪个方法的时候报错呢? 于是有了这篇文章的探索

  • 目标: 如何根据 callData 解析出调用函数

  • 内容:从合约小白的角度,从哈希函数的前世今生开始讲起。如果你已经很了解这部分内容,可以直接划到底。
    -用到的库: ethers \ foundry

在这里插入图片描述

哈希函数的前世今生

这一个部分直接引用 WTF 课程里对哈希函数的描述,讲解的很详细。 感谢社区的力量 github.com/AmazingAng/WTFSolidity


哈希函数(hash function)是一个密码学概念,它可以将任意长度的消息转换为一个固定长度的值,这个值也称作哈希(hash)。这一讲,我们简单介绍一下哈希函数及在solidity的应用

一个好的哈希函数应该具有以下几个特性

  • 单向性:从输入的消息到它的哈希的正向运算简单且唯一确定,而反过来非常难,只能靠暴力枚举。
  • 灵敏性:输入的消息改变一点对它的哈希改变很大。
  • 高效性:从输入的消息到哈希的运算高效。
  • 均一性:每个哈希值被取到的概率应该基本相等。
  • 抗碰撞性:
    • 弱抗碰撞性:给定一个消息x,找到另一个消息x'使得hash(x) = hash(x')是困难的。
    • 强抗碰撞性:找到任意xx',使得hash(x) = hash(x')是困难的。

Hash的应用

  • 生成数据唯一标识
  • 加密签名
  • 安全加密

Keccak256

Keccak256函数是solidity中最常用的哈希函数,用法非常简单:

哈希 = keccak256(数据);

Keccak256和sha3

这是一个很有趣的事情:

  1. sha3由keccak标准化而来,在很多场合下Keccak和SHA3是同义词,但在2015年8月SHA3最终完成标准化时,NIST调整了填充算法。所以SHA3就和keccak计算的结果不一样,这点在实际开发中要注意。
  2. 以太坊在开发的时候sha3还在标准化中,所以采用了keccak,所以Ethereum和Solidity智能合约代码中的SHA3是指Keccak256,而不是标准的NIST-SHA3,为了避免混淆,直接在合约代码中写成Keccak256是最清晰的。

生成函数哈希

介绍完定义,我们回归到文章主题,第一步,如何把 balanceOf(address) => 0x70a08231

  • ethers库里提供了两种方式
  1. ethers.utils.id('balanceOf(address)') 可以看到输入一个 text, 会返回一个 KECCAK256 的哈希
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L6OiB8Te-1683731069929)(Img/img_2.png)]

  2. 先将 String 转换成 Utf8Bytes 的格式,然后再用 keccak256 哈希加密. 这里要注意不能直接 ethers.utils.keccak256(balanceOf(address)) 这种方式会报错,keccak256 只支持 DataHexstring 格式的转换

    在这里插入图片描述

const textToUtf8Bytes = ethers.utils.toUtf8Bytes('balanceOf(address)')
const hashResult = ethers.utils.keccak256(textToUtf8Bytes)
  1. 补充上面 textToUtf8Bytes 可以用 ethers.utils.toUtf8String 反解出 String

输出如下,除开 0x 的前四个bytes 70a08231 为我们要的目标函数的哈希:

在这里插入图片描述

反解哈希函数

上面我们获得了函数的哈希,那么现在到第二步,如何把 0x70a08231 => balanceOf(address)

  • 反解也是两种方式 (可能不全,我目前只知道这两个办法)
  • 第一种: bytes4_signature 可以理解为一个巨大的 Text Signature 🆚 Bytes Signature 的数据库,里面会定时去扫链上的合约,并将他们对应的 哈希值 与 方法名 存下来。能满足我们大多数开发的需求
  • 第二种,用命令行解密。
    • Step1: instal foundry
    • Step2: cast 4b 70a08231

在这里插入图片描述

补充知识:前端仔会在哪里用到哈希函数?

答: EIP-165 规范文章

pragma solidity ^0.4.20;

interface ERC165 {
    /// @notice 查询一个合约时候实现了一个接口
    /// @param interfaceID  参数:接口ID, 参考上面的定义
    /// @return true 如果函数实现了 interfaceID (interfaceID 不为 0xffffffff )返回true, 否则为 false
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

EIP-165 中 提议了标准化接口的概念,并标准化了接口标识。 这么说可能有些抽象。 翻译一下就是我们可以通过调用这个方法,知道该合约是否支持某个接口。 比如 对于 一个 ERC-721 标准的 NFT 来说, 我怎么知道他是否兼容支持 ERC-2981 呢 ?

  • 首先明确 ERC-2981 对于 ERC-721 多了哪些能力?
    • 可以为 NFT 设置版税, 新增了 royaltyInfo(uint256,uint256) 查询方法
    • 那么我们就可以写下面这么一个函数,来判断 NFT 的 Fee
    • 因为 function 定义了 supportsInterface 需要传入一个 bytes4 类型的数据,所以我们传入 0x2a55205a, 对应 royaltyInfo(uint256,uint256)。 如果返回 true, 则说明 这个 NFT 兼容了 ERC-2981 标准,我们可以查看它对应的版税费率。
export const checkNftFeeAndGetFee = async ({ address, signer, tokenId }) => {
  const abi = ["function supportsInterface(bytes4) public view returns(bool)"];
  const checkContract = await createContract(address, abi, signer);
  const isSupportErc2981 = await checkContract.supportsInterface(0x2a55205a);
  let fee = 0;
  if (isSupportErc2981) {
    const nftContract = await createContract(address, erc2981ABI, signer);
    const result = await nftContract.royaltyInfo(
      tokenId,
      "100000000000000000000" // 100 * 10 ** 18, 因为要算费率,直接按100块钱算,返回多少就是对应的费率,比如 1 就是 1% 费率,
    );
    fee = Number(result?.royaltyAmount) / 10 ** 18;
  } else {
    fee = 0;
  }
  return fee.toString();
};

结尾

文章及代码demo同步发布在 我的github仓库 欢迎 star / fork /…, 互相交流学习

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

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

相关文章

【网络基础知识概念】路由器,交换机,无线AP,DHCP,DNS,WAN接口和LAN接口是什么?(附实物图详解)

【写在前面】其实在做一些试题的时候,经常会有些概念性的东西完全不清楚,今天我就带大家整理一下,交换机是啥?路由器是啥?无线AP是啥?ADSL又是什么,啥叫DHCP,DNS又是啥?W…

改进YOLOv5 | C3模块改动篇 | 轻量化设计 |骨干引入动态卷积|CondConv

CondConv: Conditionally Parameterized Convolutions for Efficient Inference 卷积是当前CNN网络的基本构成单元之一,它的一个基本假设是:卷积参数对所有样例共享。作者提出一种条件参数卷积,它可以为每个样例学习一个特定的卷积核参数,通过替换标准卷积,CondConv可以提…

shell脚本之“sort“、“uniq“、“tr“、“cut“命令详解

文章目录 sort命令uniq命令tr命令cut命令 sort命令 以行为单位对文件内容进行排序,也可以根据不同的数据类型来排序. 比较原则:从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出. 语法格式 sort [选项] 参数 cat …

c++ this指针

this指针介绍: c中成员变量和成员函数分开存储,每一个非静态成员函数只会有一个实例,多个同类型对象共用这一个成员函数。那么代码怎么区分哪个对象调用自己呢?this指针由此应运而生。 c通过提供对象指针,this指针。…

2020年下半年软件设计师下午试题

【试题四】希尔排序 【说明】 希尔排序算法又称最小增量排序算法,其基本思想是: 步骤1 :构造一个步长序列delta、deltak、 deltak ,其中delta1n/2 ,后面的每个delta是前一个的1/2 , deltak1; 步骤2 :根…

【shell脚本里的命令】

目录 一、sort命令1.1、命令演示 二、unip命令1、命令演示1、列题:2、使用脚本来查看用户有没有被恶意登录,查看登录用户的对应ip地址 三、tr命令1.1、命令演示1.2、使用tr命令对数组进行排序 五、从Windows里拉文件到Linux系统中要做的潜在条件六、cut命令 一、sor…

vue 阻止事件冒泡和捕获

文章目录 1. js 事件的三阶段2. js 阻止事件冒泡,捕获3、JavaScript基础知识:preventDefault和stopPropagationpreventDefault()事件方法stopPropagation()事件方法 click.stop : 阻止事件冒泡 click.prevent : 阻止事件默认行为 click.self : 事件只作用…

卡尔曼滤波器-公式推导 | 原理分析 | 将卡尔曼滤波器在MatLab中简单实现

目录 1.状态转移2.协方差矩阵3.噪声协方差矩阵的传递4.观测矩阵5.状态更新6.噪声协方差矩阵的更新7.在MatLab中实现卡尔曼滤波器1.状态转移 卡尔曼滤波器又称为最佳线性滤波器。优点有实现简单、纯时域滤波器、不需要进行频域变换等。 假设有一辆汽车在路上行驶,用位置和速度…

《学会提问》读后感

文章目录 批判性思维是什么?《学会提问》讲了什么?怎么成为一个批判性思维者? 批判性思维是什么? ​ 批判性思维是什么?在接触之前我是没有概念的,先借用百度百科一句话:批判性思维&#xff08…

Android 引入hunter-timing监测UI主线程函数运行时耗时,Java(2)

Android 引入hunter-timing监测UI主线程函数运行时耗时,Java(2) (1)在工程的根build.gradle文件配置: buildscript {repositories {mavenCentral()}dependencies {classpath cn.quinnchen.hunter:hunter-t…

c语言实现三子棋(思路+项目展示+源代码)

📕博主介绍:目前大一正在学习c语言,数据结构,计算机网络。 c语言学习,是为了更好的学习其他的编程语言,C语言是母体语言,是人机交互接近底层的桥梁。 本章来写一个三子棋小游戏吧。 让我们开启c…

java版本微信机器人使用教程V1.0

大家好,我是雄雄,欢迎关注微信公众号雄雄的小课堂 现在是:2023年5月10日17:57:02 前言 历经好多天,java版本的微信机器人终于写完了初版了,接下来开放注册,大家先试用一下,有问题可以提出来&a…

配置Windows终端直接执行Python脚本,无需输入“python“

配置Windows终端直接执行Python脚本,无需输入"python" 1. 将Python加入环境变量2. 将Python后缀加入环境变量PATHEXT中3. 修改Python脚本的默认打开方式4. *将Python脚本命令加入环境变量*5. 测试 在Linux系统中,在Python脚本的开头指定Python…

Java基础(二十二):File类与IO流

Java基础系列文章 Java基础(一):语言概述 Java基础(二):原码、反码、补码及进制之间的运算 Java基础(三):数据类型与进制 Java基础(四):逻辑运算符和位运算符 Java基础(五):流程控制语句 Java基础(六)&#xff1…

MySQL的内,外,自连接复习

目录 1.找出每个员工的薪资等级,要求显示员工名,薪资,薪资等级 2.查询员工的上级领导,要求显示员工名和对应的领导名 外连接的引入 五月 1.找出每个员工的薪资等级,要求显示员工名,薪资,薪资等…

【笔试强训选择题】Day10.习题(错题)解析

作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:笔试强训选择题 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!! 文章目录…

Vue电商项目--开发ListContainer模块

swiper基本使用 上节,我们使用了mock把数据成功的存储到了banner组件当中。现在先复习一下swiper这个轮播图插件的使用 Swiper中文网-轮播图幻灯片js插件,H5页面前端开发 下载swiper 首先我们需要css和js。然后把这俩个捞走 看说明书,引入js和css 这里…

深度学习笔记之卷积神经网络(三)卷积示例与池化操作

深度学习笔记之卷积神经网络——卷积示例与池化操作 引言卷积神经网络:卷积层卷积层的计算过程 池化层描述池化层的作用——降低模型复杂度,防止过拟合池化层执行过程池化层代码示例 池化层的作用——平移不变性卷积加池化作为一种无限强的先验池化层的反…

在vs2019中调试qt5.9.3为例

vs2019中其实可以调试qt,此环境配置qt5.9.3和vs2019,当前配置,作为一个记录,也方便大家查看。 vs配置qt环境 首先需要配置好qt在vs2019,可以打开网址https://download.qt.io/archive/vsaddin/2.8.1/, 我准…

【C++】继承和多态、public、private、protected、重写

区分继承与多态、辨别public、protected、private 继承与多态的概念继承与多态的区别与联系区别:联系:示例结果: 继承和访问的权限说明示例:结果 结论 继承与多态的概念 面向对象三大原则:封装、继承、多态。继承是一种…