Michael.W基于Foundry精读Openzeppelin第14期——SafeMath.sol

Michael.W基于Foundry精读Openzeppelin第14期——SafeMath.sol

      • 0. 版本
        • 0.1 SafeMath.sol
      • 1. 目标合约
      • 2. 代码精读
        • 2.1 tryAdd(uint256 a, uint256 b) && trySub(uint256 a, uint256 b) && tryMul(uint256 a, uint256 b) && tryDiv(uint256 a, uint256 b) && tryMod(uint256 a, uint256 b)
        • 2.2 add(uint256 a, uint256 b) && mul(uint256 a, uint256 b)
        • 2.3 sub(uint256 a, uint256 b) && div(uint256 a, uint256 b) && mod(uint256 a, uint256 b) && sub(uint256 a, uint256 b, string memory errorMessage) && div( uint256 a, uint256 b, string memory errorMessage) && mod(uint256 a, uint256 b, string memory errorMessage)

0. 版本

[openzeppelin]:v4.8.3,[forge-std]:v1.5.6

0.1 SafeMath.sol

Github: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.3/contracts/utils/math/SafeMath.sol

SafeMath库是对solidity中uint256的加、减、乘、除和取模运算的一层封装。由于solidity 0.8之前的uint256运算是不做溢出检查,许多基于0.8版本之前的项目都会使用该库。0.8版本之后solidity编译器内置了整形数溢出检查,所以SafeMath也不再被广泛使用。

注:此版本的SafeMath库必须是基于solidity 0.8及之后的编译器版本使用。

1. 目标合约

封装SafeMath library成为一个可调用合约:

Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/src/utils/math/MockSafeMath.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;import "openzeppelin-contracts/contracts/utils/math/SafeMath.sol";contract MockSafeMath {using SafeMath for uint;function tryAdd(uint a, uint b) external pure returns (bool, uint) {return a.tryAdd(b);}function trySub(uint a, uint b) external pure returns (bool, uint) {return a.trySub(b);}function tryMul(uint a, uint b) external pure returns (bool, uint) {return a.tryMul(b);}function tryDiv(uint a, uint b) external pure returns (bool, uint) {return a.tryDiv(b);}function tryMod(uint a, uint b) external pure returns (bool, uint) {return a.tryMod(b);}function add(uint a, uint b) external pure returns (uint){return a.add(b);}function sub(uint a, uint b) external pure returns (uint) {return a.sub(b);}function mul(uint a, uint b) external pure returns (uint){return a.mul(b);}function div(uint a, uint b) external pure returns (uint) {return a.div(b);}function mod(uint a, uint b) external pure returns (uint) {return a.mod(b);}function sub(uint a,uint b,string memory errorMessage) external pure returns (uint){return a.sub(b, errorMessage);}function div(uint a,uint b,string memory errorMessage) external pure returns (uint) {return a.div(b, errorMessage);}function mod(uint a,uint b,string memory errorMessage) external pure returns (uint) {return a.mod(b, errorMessage);}
}

全部foundry测试合约:

Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/test/utils/math/SafeMath.t.sol

2. 代码精读

2.1 tryAdd(uint256 a, uint256 b) && trySub(uint256 a, uint256 b) && tryMul(uint256 a, uint256 b) && tryDiv(uint256 a, uint256 b) && tryMod(uint256 a, uint256 b)

  • tryAdd(uint256 a, uint256 b):计算两数之和。如果加法产生溢出,返回false和0,否则返回true和结果;
  • trySub(uint256 a, uint256 b):计算两数之差。如果减法产生溢出,返回false和0,否则返回true和结果;
  • tryMul(uint256 a, uint256 b):计算两数之积。如果乘法产生溢出,返回false和0,否则返回true和结果;
  • tryDiv(uint256 a, uint256 b):计算两数之商。如果除法产生溢出,返回false和0,否则返回true和结果;
  • tryMod(uint256 a, uint256 b):计算两数的取模运算,即求余数。如果模运算产生溢出,返回false和0,否则返回true和结果。
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {// 关闭solidity 0.8的整数运算溢出检查unchecked {// 计算和uint256 c = a + b;// 如果a>和,则发生整形溢出。返回false和0if (c < a) return (false, 0);// 返回true和计算结果return (true, c);}}function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {// 关闭solidity 0.8的整数运算溢出检查unchecked {// 如果减数>被减数,发生整形溢出。返回false和0if (b > a) return (false, 0);// 返回true和计算结果 return (true, a - b);}}function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {// 关闭solidity 0.8的整数运算溢出检查unchecked {// 如果a为0,乘积必然为0。返回true和0if (a == 0) return (true, 0);// 计算乘积cuint256 c = a * b;// 做除法检查是否溢出。如果乘积c除以a不等于b,产生溢出。返回false和0if (c / a != b) return (false, 0);// 返回true和乘积creturn (true, c);}}function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {// 关闭solidity 0.8的整数运算溢出检查unchecked {// 如果除数为0,直接返回false和0if (b == 0) return (false, 0);// 由于被除数和非0除数都是uint256,必然除法不会产生溢出。直接返回true和运算结果return (true, a / b);}}// 注:同tryDiv()的内在判断逻辑一致function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {// 关闭solidity 0.8的整数运算溢出检查unchecked {// 如果除数为0,直接返回false和0if (b == 0) return (false, 0);// 由于被除数和非0除数都是uint256,必然除法不会产生溢出。直接返回true和取模运算结果return (true, a % b);}}

foundry代码验证

contract SafeMathTest is Test {MockSafeMath msm = new MockSafeMath();function test_TryAdd() external {(bool flag,uint res) = msm.tryAdd(1, 2);assertTrue(flag);assertEq(res, 3);// overflow(flag, res) = msm.tryAdd(type(uint).max, 1);assertFalse(flag);assertEq(res, 0);}function test_TrySub() external {(bool flag,uint res) = msm.trySub(3, 1);assertTrue(flag);assertEq(res, 2);// overflow(flag, res) = msm.trySub(1, 2);assertFalse(flag);assertEq(res, 0);}function test_TryMul() external {(bool flag,uint res) = msm.tryMul(2, 3);assertTrue(flag);assertEq(res, 6);// overflow(flag, res) = msm.tryMul(type(uint).max, 2);assertFalse(flag);assertEq(res, 0);}function test_TryDiv() external {(bool flag,uint res) = msm.tryDiv(7, 2);assertTrue(flag);assertEq(res, 3);// overflow(flag, res) = msm.tryDiv(1, 0);assertFalse(flag);assertEq(res, 0);}function test_TryMod() external {(bool flag,uint res) = msm.tryMod(7, 2);assertTrue(flag);assertEq(res, 1);// overflow(flag, res) = msm.tryMod(1, 0);assertFalse(flag);assertEq(res, 0);}
}

2.2 add(uint256 a, uint256 b) && mul(uint256 a, uint256 b)

  • add(uint256 a, uint256 b):计算两数之和。如果加法产生溢出,直接revert;
  • mul(uint256 a, uint256 b):计算两数之积。如果乘法产生溢出,直接revert。
    function add(uint256 a, uint256 b) internal pure returns (uint256) {// 封装solidity内置"+"运算符return a + b;}function mul(uint256 a, uint256 b) internal pure returns (uint256) {// 封装solidity内置"*"运算符return a * b;}

foundry代码验证

contract SafeMathTest is Test {MockSafeMath msm = new MockSafeMath();function test_Add() external {assertEq(msm.add(1, 2), 3);// overflowvm.expectRevert();msm.add(type(uint).max, 1);}function test_Mul() external {assertEq(msm.mul(3, 2), 6);// overflowvm.expectRevert();msm.mul(type(uint).max, 2);}
}

2.3 sub(uint256 a, uint256 b) && div(uint256 a, uint256 b) && mod(uint256 a, uint256 b) && sub(uint256 a, uint256 b, string memory errorMessage) && div( uint256 a, uint256 b, string memory errorMessage) && mod(uint256 a, uint256 b, string memory errorMessage)

  • sub(uint256 a, uint256 b):计算两数之差。如果减法产生溢出,直接revert;
  • div(uint256 a, uint256 b):计算两数之商。如果除法产生溢出(除数为0),直接revert;
  • mod(uint256 a, uint256 b):计算两数的余数。如果除法产生溢出(除数为0),直接revert;
  • sub(uint256 a, uint256 b, string memory errorMessage):计算两数之差。如果产生溢出,以自定义消息revert;
  • div( uint256 a, uint256 b, string memory errorMessage):计算两数之商。如果产生溢出,以自定义消息revert;
  • mod(uint256 a, uint256 b, string memory errorMessage):计算两数的余数。如果产生溢出,以自定义消息revert。
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {// 封装solidity内置"-"运算符return a - b;}function div(uint256 a, uint256 b) internal pure returns (uint256) {// 封装solidity内置"/"运算符return a / b;}function mod(uint256 a, uint256 b) internal pure returns (uint256) {// 封装solidity内置"%"运算符return a % b;}// 注:该方法已弃用,因为自定义revert消息作为参数会引起更多额外的memory分配。如果想自定义溢出消息,可以使用trySub()function sub(uint256 a,uint256 b,string memory errorMessage) internal pure returns (uint256) {unchecked {// 如果减数>被减数,以errorMessage revert// 注:由于这里调用了opcode `revert`,在发生revert时会返还剩余gas。而使用solidity内置减法发生revert时,会调用不合法opcode直接消耗掉剩余的gasrequire(b <= a, errorMessage);// 返回二者之差return a - b;}}// 注:该方法已弃用,因为自定义revert消息作为参数会引起更多额外的memory分配。如果想自定义溢出消息,可以使用tryDiv()function div(uint256 a,uint256 b,string memory errorMessage) internal pure returns (uint256) {// 关闭solidity 0.8的整数运算溢出检查unchecked {// 如果除数=0,以errorMessage revert// 注:由于这里调用了opcode `revert`,在发生revert时会返还剩余gas。而使用solidity内置除法发生revert时,会调用不合法opcode直接消耗掉剩余的gasrequire(b > 0, errorMessage);// 返回二者之商return a / b;}}// 注:该方法已弃用,因为自定义revert消息作为参数会引起更多额外的memory分配。如果想自定义溢出消息,可以使用tryMod()function mod(uint256 a,uint256 b,string memory errorMessage) internal pure returns (uint256) {// 关闭solidity 0.8的整数运算溢出检查unchecked {// 如果除数=0,以errorMessage revert// 注:由于这里调用了opcode `revert`,在发生revert时会返还剩余gas。而使用solidity内置取模运算符发生revert时,会调用不合法opcode直接消耗掉剩余的gasrequire(b > 0, errorMessage);// 返回两数的余数return a % b;}}
}

foundry代码验证

contract SafeMathTest is Test {MockSafeMath msm = new MockSafeMath();function test_Sub() external {assertEq(msm.sub(3, 2), 1);// overflowvm.expectRevert();msm.sub(1, 2);// with error messageassertEq(msm.sub(3, 2, "error message"), 1);vm.expectRevert("error message");msm.sub(1, 2, "error message");}function test_Div() external {assertEq(msm.div(7, 2), 3);// overflowvm.expectRevert();msm.div(1, 0);// with error messageassertEq(msm.div(7, 2, "error message"), 3);vm.expectRevert("error message");msm.div(1, 0, "error message");}function test_Mod() external {assertEq(msm.mod(7, 2), 1);// overflowvm.expectRevert();msm.mod(1, 0);// with error messageassertEq(msm.mod(7, 2, "error message"), 1);vm.expectRevert("error message");msm.mod(1, 0, "error message");}
}

ps:
本人热爱图灵,热爱中本聪,热爱V神。
以下是我个人的公众号,如果有技术问题可以关注我的公众号来跟我交流。
同时我也会在这个公众号上每周更新我的原创文章,喜欢的小伙伴或者老伙计可以支持一下!
如果需要转发,麻烦注明作者。十分感谢!

在这里插入图片描述

公众号名称:后现代泼痞浪漫主义奠基人

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

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

相关文章

LlaMA2微调实战

LLaMA2-SFT LLaMA2-SFT, Llama-2-7B微调(transformers)/LORA(peft)/推理 Gtihub地址 https://github.com/yongzhuo/Llama2-SFT prompt text_1 f"".join(["[INST] <<SYS>>\n ""You are a helpful, respectful and honest assista…

ubuntu远程控制小车 运行rviz时报错

我买的是wheeltec的小车&#xff0c;测试rgbd相机时想在ubuntu上的rviz中显示小车的姿态和看到的rgb和depth图&#xff0c;但是ubuntu中rostopic list和rviz都找不到小车发布的话题信息&#xff0c;运行rqt_image_view时可以显示图片信息。 最终wheeltec的技术人员lucas帮我找了…

nodejs+vue+elementui汽车销售网站

前端技术&#xff1a;nodejsvueelementui,视图层其实质就是vue页面&#xff0c;通过编写vue页面从而展示在浏览器中&#xff0c;编写完成的vue页面要能够和控制器类进行交互&#xff0c;从而使得用户在点击网页进行操作时能够正常。 可以设置中间件来响应 HTTP 请求。 Express …

Kafka 入门到起飞 - Kafka怎么做到保障消息不会重复消费的? 消费者组是什么?

Kafka怎么做到避免消息重复消费的&#xff1f; 消费者组是什么&#xff1f; 消费者&#xff1a; 1、订阅Topic&#xff08;主题&#xff09; 2、从订阅的Topic消费&#xff08;pull&#xff09;消息&#xff0c; 3、将消费消息的offset&#xff08;偏移量&#xff09;保存在K…

西安电子科技大学

前言 本篇文章投稿与以下活动 【西安城市开发者社区】探索西安高校&#xff1a;展现历史与创新的魅力 资料参考与百度百科 学校简介 西安电子科技大学&#xff08;Xidian University&#xff09;&#xff0c;简称“西电”&#xff0c;位于陕西省西安市&#xff0c;是中央部…

14.Netty源码之模拟简单的HTTP服务器

highlight: arduino-light 简单的 HTTP 服务器 HTTP 服务器是我们平时最常用的工具之一。同传统 Web 容器 Tomcat、Jetty 一样&#xff0c;Netty 也可以方便地开发一个 HTTP 服务器。我从一个简单的 HTTP 服务器开始&#xff0c;通过程序示例为你展现 Netty 程序如何配置启动&a…

2023年全国程序员薪酬排行天梯榜

文章目录 ⭐️ 2023年全国程序员薪酬排行天梯榜 在过去很长的一段时间内&#xff0c;网上总有一个声音&#xff1a;“大厂裁员”、“程序员内卷严重”、“程序员人员过盛”、“35岁中年危机”、“码农吃的青春饭”、“互联网寒冬” 等等等等。 讲道理&#xff0c;我对这种人为的…

LLM Data Pipelines: 解析大语言模型训练数据集处理的复杂流程

编者按&#xff1a;在训练大语言模型的过程中,构建高质量的训练数据集是非常关键的一步&#xff0c;但关于构建大模型训练所需数据集的通用数据处理流程&#xff08;Data pipelines)的相关资料极为稀少。 本文主要介绍了基于Common Crawl数据集的数据处理流程。首先,文章概述了…

复现YOLOv8改进最新MPDIoU:有效和准确的边界盒回归的损失,打败G/E/CIoU,效果明显!!!

MPDIoU: A Loss for Efficient and Accurate Bounding Box Regression 论文简介MPDIoU核心设计思路论文方法实验部分加入YOLOv5代码论文地址:https://arxiv.org/pdf/2307.07662.pdf 论文简介 边界盒回归(Bounding box regression, BBR)广泛应用于目标检测和实例分割,是目标…

【业务功能篇56】SpringBoot 日志SLF4J Logback

3.5.1 日志框架分类与选择 3.5.1.1 日志框架的分类 日志门面 (日志抽象)日志实现JCL(Jakarta Commons Logging) SLF4J(Simple Logging Facade for Java)Jul(Java Util Logging) , Log4j , Log4j2 , Logback 记录型日志框架 Jul (Java Util Logging)&#xff1a;JDK中的日志…

Python实现指定区域桌面变化监控并报警

在这篇博客中&#xff0c;我们将使用Python编程语言和一些常用的库来实现一个简单的区域监控和变化报警系统。我们将使用Tkinter库创建一个图形界面&#xff0c;允许用户选择监控区域&#xff0c;并使用OpenCV库进行图像处理和相似性比较&#xff0c;以检测区域内的变化&#x…

基于IP地址的证书实现https

基于IP地址实现传递数据的&#xff0c;默认的HTTP很容易被不法分子劫持数据&#xff0c;网络防洪是当下的互联网为确保安全&#xff0c;要用HTTPS协议更为妥当。 使用IP地址申请证书的主要条件&#xff0c;必须在申请认证过程&#xff0c;开放IP地址外网可以访问&#xff0c;包…

全方位支持图文和音视频、100+增强功能,Facebook开源数据增强库AugLy

Facebook 近日开源了数据增强库 AugLy&#xff0c;包含四个子库&#xff0c;每个子库对应不同的模态&#xff0c;每个库遵循相同的接口。支持四种模态&#xff1a;文本、图像、音频和视频。 最近&#xff0c;Facebook 开源了一个新的 Python 库——AugLy&#xff0c;该库旨在帮…

C语言每日一题:4.消失的数字+数字在升序数组中出现的次数+整数转换

消失的数字&#xff1a; 思路1&#xff1a;排序遍历 1.使用qsort排序数组判断当前数值1是否是数组下一个元素的数值。 2.如果是一直循环注意数组越界&#xff0c;如果不是那么当前的数组的数值1就是消失的数。 3.存在0——n的数字是第n个数没有了。循环过程中从头到尾也找不到这…

Zabbix监控之分布式部署

文章目录 Zabbix监控之分布式部署zabbix proxy概述部署zabbix-proxy节点规划基础环境准备安装proxy以及数据库配置数据库添加服务端host解析修改zabbix-proxy配置文件启动代理服务器 zabbix页面(1)在zabbix页面添加代理(2)zabbix-agent连接proxy Zabbix监控之分布式部署 zabbi…

【LeetCode】101.对称二叉树

题目 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false提示&#xff1a; 树中节点数…

几个影响 cpu cache 性能因素及 cache 测试工具介绍

》内核新视界文章汇总《 文章目录 1 cache 性能及影响因素1.1 内存访问和性能比较1.2 cache line 对性能的影响1.3 L1 和 L2 缓存大小1.4 指令集并行性对 cache 性能的影响1.5 缓存关联性对 cache 的影响1.6 错误的 cacheline 共享 (缓存一致性)1.7 硬件设计 2 cpu cache benc…

让企业出海支付流程更加安全,亚马逊云科技推出支付加密服务

在咖啡店买一杯咖啡&#xff0c;在电商平台下单一件商品&#xff0c;其消费流程背后&#xff0c;都要涉及到金融支付的多个环节&#xff0c;而其中对金融数据存储和流通的加密则是保障金融安全的重要环节。 加密是保障消费者支付流程安全的最大挑战。亚马逊云科技首席安全布道…

数仓学习---15、数据仓库工作流调度

1、数据仓库工作流调度 1.1 调度工具部署 工具部署链接 1.2 新数据生成 1.2.1 用户行为日志 1、启动日志采集通道&#xff0c;包括Kafka、Flume等 &#xff08;1&#xff09;启动Zookeeper zk.sh start&#xff08;2&#xff09;启动Kafka kf.sh start&#xff08;3&…

【ROS第一讲】一、创建工作空间

【ROS第一讲】一、创建工作空间 一、工作空间1.src&#xff1a;2.build&#xff1a;3.devel&#xff1a;4.install: 二、创建工作空间1.工作空间的编译2.配置环境变量&#xff1a; 三、创建功能包 一、工作空间 1.src&#xff1a; 放置所有功能包源码的空间 2.build&#xf…