Solidity学习 - 错误处理

文章目录

    • 前言
    • EVM错误处理机制
      • EVM错误处理的核心特性
      • 程序中的错误处理
    • 错误抛出方法
      • require()函数
        • require()触发异常的场景
        • 关键特性
      • assert()函数
        • assert()触发异常的场景
        • 关键特性
      • require() vs assert():选择指南
      • revert()函数
        • 关键特性
    • 异常捕获:try/catch
      • 外部调用异常捕获
      • 高级异常捕获
      • 注意事项

前言

在Solidity智能合约开发中,错误处理是保障合约安全和可靠性的重要环节。与传统编程语言不同,EVM(以太坊虚拟机)的错误处理机制具有独特的特性,本文将详细介绍Solidity中错误处理的核心概念、方法及最佳实践。

EVM错误处理机制

EVM错误处理的核心特性

EVM的错误处理机制与Java、JavaScript等传统语言有本质区别:当EVM执行过程中遇到错误(如数组越界、除零操作等),会触发交易回退(revert),导致整个交易的状态变更被撤销。这种机制确保了以太坊交易的原子性——所有操作要么全部成功,要么全部失败,不会出现部分状态修改的情况。

传统语言错误处理 vs EVM错误处理
┌──────────────┐     ┌──────────────┐
│ 开始执行      │     │ 开始执行      │
│              │     │              │
│ 操作1 生效    │     │ 操作1 生效    │
│              │     │              │
│ 发生错误      │     │ 发生错误      │
│              │     │              │
│ 操作2 未执行  │     │ 回退到初始状态 │
│              │     │              │
└──────────────┘     └──────────────┘

程序中的错误处理

在合约代码中,错误处理主要通过条件检查、错误抛出和异常捕获来实现。无论主动抛出错误还是遇到未处理的情况,EVM都会回滚交易。以下是Solidity中错误处理的核心方法:

错误抛出方法

Solidity提供了三种抛出异常的方式:require()assert()revert(),每种方式适用于不同的场景。

require()函数

require()函数用于在执行逻辑前检查输入参数或合约状态是否满足条件,不满足时抛出异常并回滚交易。

pragma solidity >=0.8.0;
contract testRequire {function vote(uint age) public {require(age >= 18, "只有18岁以上才可以投票");// 投票逻辑...}function transferOwnership(address newOwner) public {require(owner() == msg.sender, "调用者不是Owner");// 所有权转移逻辑...}
}
require()触发异常的场景
  • 消息调用的函数未正确结束(耗尽gas、无匹配函数或自身抛出异常)
  • 使用new关键字创建合约失败
  • 调用不存在的外部函数
  • 向不可接收ETH的合约转账或调用无payable修饰符的函数
关键特性
  • 触发REVERT操作码回滚交易
  • 未使用的Gas返回给交易发起者
  • 适用于检查用户输入、外部调用返回值和合约状态

assert()函数

assert()函数用于检查内部逻辑的正确性,假设条件始终为真,否则表示程序出现未知错误。

pragma solidity >=0.8.0;
contract testAssert {bool public inited;function checkInitValue() internal {// 假设inited永远为falseassert(!inited);// 其他逻辑...}
}
assert()触发异常的场景
  • 数组或固定长度bytesN索引越界
  • 除零或模零运算
  • 负数位移
  • 枚举类型转换错误
  • 调用未初始化的内部函数类型变量
关键特性
  • 在Solidity 0.8.0及以上版本触发REVERT操作码
  • 适用于检查溢出错误和不应该发生的异常情况
  • 可被分析工具(如STMChecker)用于错误检测

require() vs assert():选择指南

场景优先使用require()优先使用assert()
检查用户输入
检查外部调用返回值
检查合约状态
函数开头条件检查
检查溢出错误
检查不应该发生的情况
函数中间/结尾检查

revert()函数

revert()函数用于显式回退交易,支持自定义错误和错误消息。

pragma solidity ^0.8.4;
contract testRevert {address public owner;error NotOwner(); // 自定义错误function transferOwnership(address newOwner) public {if (owner != msg.sender) revert NotOwner();owner = newOwner;}
}
关键特性
  • 两种形式:revert CustomError(arg1, arg2)revert(string memory reason)
  • 自定义错误(如error NotOwner())消耗Gas更低(仅4字节编码)
  • 功能与require()等价,但提供更灵活的错误处理方式

异常捕获:try/catch

外部调用异常捕获

通过try/catch可以捕获外部调用的异常,避免交易因外部合约错误而回退。

contract CalledContract {function getTwo() external returns (uint256) {return 2;}
}contract TryCatcher {CalledContract public externalContract;function executeEx() public returns (uint256, bool) {try externalContract.getTwo() returns (uint256 v) {uint256 newValue = v + 2;return (newValue, true);} catch {// 处理异常}}
}

高级异常捕获

catch支持不同子句捕获不同类型的异常:

contract TryCatcher {event ReturnDataEvent(bytes someData);event CatchStringEvent(string someString);event SuccessEvent();function execute() public {try externalContract.someFunction() {emit SuccessEvent();} catch Error(string memory revertReason) {emit CatchStringEvent(revertReason); // 捕获require/revert的字符串错误} catch (bytes memory returnData) {emit ReturnDataEvent(returnData); // 捕获其他类型异常}}
}

注意事项

  • try/catch仅适用于捕获外部调用的异常,无法捕获内部代码异常
  • 本地变量仅在trycatch块内有效
  • 错误提示转换为bytes失败时,try/catch会回退整个交易

想要了解更详细的内容,可以访问错误处理。

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

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

相关文章

如何永久删除Android上的短信[无法恢复]

当您不再保留 Android 设备时,您将需要彻底删除所有私人数据,包括短信。因此,有必要了解如何永久删除Android上的短信。现在,阅读本指南,掌握消除信息的实用方法。 第 1 部分:如何一键永久删除 Android 上的…

P12894 [蓝桥杯 2025 国 Java B] 智能交通信号灯

[Problem] \color{blue}{\texttt{[Problem]}} [Problem] 给定一个长度为 n n n 的数组 a 1 … n a_{1\dots n} a1…n​&#xff0c;进行 m m m 次一下操作&#xff1a; 给定 l , r l,r l,r&#xff0c;求出 ∑ l ≤ i < j ≤ r mex { a i , a j } \sum\limits_{l \le…

华为云Flexus+DeepSeek征文|基于华为云一键部署的 Dify-LLM 平台构建智能试卷生成助手

目录 前言 1 华为云Dify-LLM应用平台部署 1.1 一键部署平台简介 1.2 四步完成部署流程 2 接入华为云 DeepSeek 自定义大模型 2.1 ModelArts Studio 模型服务介绍 2.2 配置自定义大模型 3 创建试卷生成工具&#xff08;工作流&#xff09; 3.1 设计 DSL 工作流 3.2 工…

嵌入式硬件与应用篇---寄存器GPIO控制

在 ARM 架构中&#xff0c;通过 32 位寄存器控制 GPIO&#xff08;通用输入输出&#xff09;的核心步骤和方法可分为以下几个关键环节&#xff0c;结合不同芯片的实现差异&#xff0c;具体操作需参考对应的数据手册&#xff1a; 一、GPIO 控制的核心步骤 1. 使能 GPIO 时钟 …

Fiddler中文版抓包工具在跨域与OAuth调试中的深度应用

跨域和OAuth授权流程一直是Web和移动开发中最容易踩坑的领域。复杂的CORS配置、重定向中的Token传递、授权码流程的跳转&#xff0c;以及多域名环境下的Cookie共享&#xff0c;常常让开发者陷入调试困境。此时&#xff0c;一款能够精准捕获、修改、重放请求的抓包工具显得至关重…

React用户交互事件

在React中处理用户交互事件&#xff08;如点击、输入、提交等&#xff09;的方式与原生JavaScript类似&#xff0c;但有一些语法差异和最佳实践。以下是常见交互事件的处理方法及代码示例&#xff1a; 一、基本事件处理&#xff08;点击、输入等&#xff09; 1. 点击事件&…

DHT11 STM32 HAL驱动库 整数

dht11.h #ifndef __DHT11_H #define __DHT11_H#include "stm32f1xx_hal.h" // 根据实际芯片型号调整&#xff08;如stm32f4xx_hal.h&#xff09;// DHT11数据结构 typedef struct {GPIO_TypeDef *GPIOx; // GPIO端口&#xff08;如GPIOA&#xff09;uint16_t GP…

【Actix Web 精要】Rust Web 服务开发核心技术与实战指南

目录 一、Actix Web 核心架构解析1.1 核心组件交互流程1.2 关键组件说明&#xff1a; 二、项目初始化与配置2.1 创建项目2.2 添加依赖 (Cargo.toml)2.3 项目结构 三、核心模块实现3.1 配置管理 (src/config.rs)3.2 应用状态管理 (src/main.rs)3.3 数据模型 (src/models/user.rs…

从URL到视频:用Python和AI构建自动化内容讲解视频生成管道

摘要 本文旨在从技术层面&#xff0c;深入探讨并实践一个将任意网页链接&#xff08;如飞书文档、博客文章&#xff09;自动转换为带有配音和字幕的讲解视频的系统。我们将详细拆解整个实现流程&#xff0c;覆盖从内容抓取与解析、利用大语言模型&#xff08;LLM&#xff09;智…

Java 使用 Easy Excel 进行 Excel 数据导入导出

1. 通过 Maven 下载 Easy Excel 依赖包 在项目的 pom.xml 文件中添加以下依赖&#xff1a; <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version> <!-- 使用最新版本 -->…

国产化条码类库Spire.Barcode教程:如何使用 C# 读取 PDF 中的条码(两种方法轻松实现)

在 PDF 文档的 .NET 平台处理流程中&#xff0c;使用 C# 读取 PDF 条码 是一项常见需求&#xff0c;特别适用于处理扫描件或电子表单。无论是物流、金融、医疗还是制造行业&#xff0c;PDF 文档中经常包含用于追踪或识别的条码。这些条码可能是嵌入图像&#xff0c;也可能是矢量…

2023国赛数字取证-流量分析

数据取证 - 1 A 集团的⽹络安全监控系统发现恶意份⼦正在实施⾼级可持续攻击&#xff08;APT&#xff09;&#xff0c;并抓取了部分可疑流量包。请 您根据捕捉到的流量包&#xff0c;搜寻出⽹络攻击线索&#xff0c;分解出隐藏的恶意程序&#xff0c;并分析恶意程序的⾏为。 …

【预约小程序】-健身房预约课程小程序——仙盟创梦IDE

东方仙盟-坐拥万个代码 免费报表 阿雪技术观 让我们积极投身于技术共享的浪潮中&#xff0c;不仅仅是作为受益者&#xff0c;更要成为贡献者。无论是分享自己的代码、撰写技术博客&#xff0c;还是参与开源项目的维护和改进&#xff0c;每一个小小的举动都可能成为推动技术进…

SmartETL中数据库操作与流程解耦的设计与应用

正如ETL这个概念本身所指示的&#xff0c;数据库读写访问是ETL的最常用甚至是最主要的操作。现代信息系统的设计与运行基本都是围绕数据库展开的&#xff0c;很多应用的核心功能都是对数据库的CRUD&#xff08;创建、检索、更新、删除&#xff09;操作。 SmartETL框架设计之初…

【记录解决问题】activiti--sql 转义符设置

一、背景 %、&#xff01;、_在sql查询时需要转义&#xff0c;转义的语法 like %?2% escape ?#{escapeCharacter()}二、activiti转义配置 String wildcardEscapeClause ""; if (this.databaseWildcardEscapeCharacter ! null && this.databaseWildcard…

Unity AR构建维护系统的以AI驱动增强现实知识检索系统

本博客概述了为维护开发的AI驱动增强现实&#xff08;AR&#xff09;知识检索系统的开发过程&#xff0c;该系统集成了Unity用于AR、Python服务器用于后端处理&#xff0c;以及ChatGPT用于自然语言处理。该系统允许维护工人通过AR设备&#xff08;如HoloLens 2&#xff09;查询…

Java面向对象核心:方法值传递与封装机制精讲

文章目录 Java面向对象编程核心笔记一、方法值传递机制1. 基本数据类型传递2. 引用数据类型传递值传递总结 二、面向对象核心概念1. 类与对象关系2. 类定义规范3. 对象创建与使用 三、封装机制详解1. 封装三大要素2. 封装示例&#xff08;GirlFriend类&#xff09;3. 测试类4. …

【Actix Web】构建高性能 Rust API:Actix Web 最佳实践与进阶指南

目录 一、高性能 API 架构设计1.1 系统架构图1.2 核心组件 二、项目初始化与配置2.1 创建项目2.2 添加依赖 (Cargo.toml)2.3 配置文件 (config/default.toml) 三、核心模块实现3.1 应用状态管理 (src/state.rs)3.2 数据模型定义 (src/models.rs) 四、认证与授权系统4.1 JWT 认证…

vue项目中纯前端实现导出pdf文件,不需要后端处理。

在 Vue 项目中&#xff0c;纯前端实现导出 PDF 文件是完全可行的。通常可以借助一些 JavaScript 库来将 HTML 内容或 DOM 元素转换为 PDF 并下载&#xff0c;无需后端参与。 下面介绍几种常用的方案和实现方法&#xff1a; 推荐方案&#xff1a;使用 html2canvas jsPDF 安装…

c++虚拟内存

常见的内存困惑 当你编写C程序时&#xff0c;是否遇到过&#xff1a; vector申请200MB内存&#xff0c;但系统显示只占用20MB&#xff1f;程序在低配机器上崩溃&#xff0c;报出std::bad_alloc但内存显示充裕&#xff1f;遍历数组时特定位置耗时突然增加&#xff1f;相同代码…