Solidity基础六
生活本来就是平凡琐碎的,哪有那么多惊天动地的大事,快乐的秘诀就是不管对大事小事都要保持热情
目录
一、Solidity的特殊变量(全局)
二、Solidity的不可变量
immutable的赋值方式
三、Solidity的事件与日志
事件和日志加深理解
四、Solidity的异常处理
1.require()
2.assert()
3.revert()
4.三者使用例子
5.require、assert、revert区别
6 require、assert 使用场景
7.抛弃的异常语句和其他新增的异常语句
五、Solidity 工厂合约
一、Solidity的特殊变量(全局)
特殊变量,是全局可用的变量,提供关于区块链的信息。下面列出了常用的特殊变量
名称 | 返回 |
---|---|
blockhash(uint blockNumber) returns (bytes32) | 给定区块的哈希值 – 只适用于256最近区块, 不包含当前区块。 |
block.coinbase (address payable) | 当前区块矿工的地址 |
block.difficulty (uint) | 当前区块的难度 |
block.gaslimit (uint) | 当前区块的gaslimit |
block.number (uint) | 当前区块的number |
block.timestamp (uint) | 当前区块的时间戳,为unix纪元以来的秒 |
gasleft() returns (uint256) | 剩余 gas |
msg.data (bytes calldata) | 完成 calldata |
msg.sender (address payable) | 消息发送者 (当前 caller) |
msg.sig (bytes4) | calldata的前四个字节 (function identifier) |
msg.value (uint) | 当前消息的wei值 |
now (uint) | 当前块的时间戳 |
tx.gasprice (uint) | 交易的gas价格 |
tx.origin (address payable) | 交易的发送方 |
二、Solidity的不可变量
Solidity 的不可变量是另一种常量的表达方式。与常量类似,但是不必强制定义就需要赋值,可以在构造函数时传值,部署后无法改变。它是一种修饰符,被它修饰的变量就称之为不可变量
关键字:immutable
immutable 不可变量同样不会占用状态变量存储空间,在部署时,变量的值会被追加的运行时字节码中, 因此它比使用状态变量便宜的多,也同样带来了更多的安全性。
immutable 特性在很多时候非常有用, 最常见的如 ERC20 代币用来指示小数位置的
decimals
变量,它是一个不能修改的变量,很多时候我们需要在创建合约的时候指定它的值,这时 immutable 就大有用武之地, 类似的还有要保创建者地址、关联合约地址等。
immutable的赋值方式
第一种:定义后就赋值
数据类型 修饰符 immutable 不可变量名 = 值; 例如 :address public immutable owner = msg.sender;第二种:构造函数赋值
constructor (参数列表) {
不可变量名 = 值
}
例如:
contract Immutable {address public immutable owner; address public immutable owners; constructor(address _owner) {owner = _owner;owners=msg.sender;}
三、Solidity的事件与日志
Soliddity 事件是以太坊虚拟机(EVM)日志基础设施提供的一个便利接口。是以太坊提供的基本功能,用于将数据记录成日志保存到区块链上,用户可以自定义需要记录的数据,以及topic和索引 ,
事件和日志的区别:
事件强调行为操作、日志强调存储内容,两者是完全不同的概念
事件本质上也相当于一个特殊的函数,称为事件函数
事件在合约中可以被继承
在DAPP的应用中,如果监听了某个事件,当事件发生时,会进行回调执行一系列操作
事件的关键字:event
事件的定义格式:
event 事件名( 所要记录的参数列表 )
事件的触发格式:
emit 事件名( 所要传递给事件的参数列表 )
日志:logs
在以太坊的语境里,日志对事件和触发该事件产生的交易信息的存储
日志的组成:
- address: 交易地址
- args:事件状态变量存储对象(我们所保存的状态变量值就在这里面)
- blockHash: 哈希难度
- blockNumber: 区块号
- event: 事件名
- logIndex:
- removed:
- transactionHash: 交易哈希
- transactionIndex:
日志的作用
- 记录了事件指定的状态变量保存在区块链上的数据(记录了事件不同的状态)
- 通过日志来得到某个事件定义的状态变量中以前和现在的值
注意事项:在web3中采用事件监听所返回的值是该事件的日志,可以通过该日志.args.状态变量名 来获取日志中某个状态变量的值,而这个返回的结果是一个数组,它存储了该状态变量变化的值
当触发了事件,那么remix控制台里面的一个信息里面就有logs(日志)信息
里面记录了ages由值0变成值2
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
contract Test{int age;string a=unicode'a';event evt(int ages);function set(int _age) public returns(string memory){age=_age;emit evt(_age);return a;}
}
事件和日志加深理解
当定义的事件触发时,我们可以将事件存储到EVM的交易日志中,日志其实是区块链中一种特殊的数据结构
日志与合约关联,与合约合并存储到区块链中,只要某个区块可以访问,其相关的日志也能访问,但在合约中,我们不能直接访问日志和事件数据
可以通过日志实现简单支付验证SPV,如果一个外部实体提供了一个带有这种证明的合约,它可以检查日志是否真实存在区块链中
四、Solidity的异常处理
异常和报错
异常是指程序可以解决的一种错
报错是指程序无法解决的一种错
异常处理
Solidity处理异常和我们常见的语言不一样,solidity是通过回退状态的方式来处理错误,同时给调用者返回一个错误标识。
如果不用回退状态的方式来处理,那么异常后,状态发生错误的改变,在区块链上是需要相当大的代价来完成的
异常处理过程
发生异常时会撤销当前调用(及其所有子调用)所改变的的状态,同时给调用者返回一个错误标识
异常处理模式
早期是if....throw这个会消耗所有的gas
Solidity 0.4.10后发布了新的异常处理方法:异常处理函数
0.6.0版本还出现了try...catch
主要还是以下3种:
- require()
- assert()
- revert()
解决了以前的不好的地方,特别地, assert() 、 require() 代码会 “确保” 提高合约代码l逻辑条理的清晰,所有我们需要好好学习并区别使用它们
1.require()
格式:
require( 判断表达式 , <string>)
<string> 提供了一个自定义错误消息输出的选项
如果不满足条件也就是判断为false,则此函数调用将恢复到原始状态,此函数用于检查输入或外部组件的错误。这个方法一般是用来处理
require 可以有返回值,例如:require(condition, 'Something bad happened');。
返回:'Something bad happened'
require 的返回值不宜过长,因为返回信息需要消耗 gas。
使用 require() 的场景
- 验证一个用户输入是否合法 : require(input>20)
- 验证外部合约的调用结果,例如:require(external.send(amount))
- 判断执行一段语句的前置条件; require(balance[msg.sender]>=amount)
- require应该被经常用到
2.assert()
assert(判断表达式)
如果不满足条件也就是判断为false,则此函数调用将导致一个无效的操作码,对状态所做的任何更改将被还原,这个一般方法是用来处理内部错误的
使用 assert() 的场景
- 检查溢出
- 检查不变量
- 更改后验证状态
- 预防永远不会发生的情况
避免本不应该发生的情况出现,如程序bug
一般来说,使用assert()的频率较少,通常用于函数的结尾。
assert算是最后防线,因为它会在执行的最后来检查行为的合法性
3.revert()
revert()
一执行revert()就将中止执行并将所作的更改还原为执行前的状态
它可以搭配if分支来实现和require和assert的效果
一个交易最终只会有两种状态: cmmit & revert
适用revert的时候
因为该操作是已知不应该出现的时候,所以通常同来检查overflow/underflow、检查被修改过的状态变量是否合法,避免不应该出现的条件发生
4.三者使用例子
uint public num=0;function testRevert() public {
num++;
if (num>3){
revert(“revert返回的错误”);
}
num++;}function testAssert() public {
num++;
assert(num<13);
num++;}function testRequire()public {
num++
require( num<23,”require报错信息”);
num++;}
总结:不管是哪个回退,都是回退到不满足条件前满足条件的状态
5.require、assert、revert区别
require、assert、revert共同点:
assert()与require()语句都需要满足括号中的条件,才能进行后续操作,若不满足则抛出错误。而revert()就抛出错误
以下三个语句的功能完全相同:
// revert if(msg.sender != owner) { revert();} // require require(msg.sender == owner);// assert assert(msg.sender == owner);require、assert 不同点
assert(false) 编译为 0xfe,这是一个无效的操作码,所以会消耗掉所有剩余的 gas,并恢复所有的操作。
require(false) 编译为 0xfd,这是revert()的操作码,所以会退还所有剩余的 gas,同时可以返回一个自定义的报错信息。
同样作为判断一个条件是否满足的函数,require会回退剩下的gas,而assert会烧掉所有的gas
所以require 的 gas 消耗要小于 assert,而且可以有返回值,使用更为灵活。
6 require、assert 使用场景
- require() 函数用于检测输入变量或状态变量是否满足条件,以及验证调用外部合约的返回值。
- require() 语句的失败报错,应该被看作一个正常的判断语句流程不能通过的事件。
- assert()语句的失败报错,意味着发生了代码层面的错误事件,很大可能是合约中有一个bug需要修复
基本上,require() 应该用于检查条件,而 assert() 只是为了防止发生任何非常糟糕的事情。
7.抛弃的异常语句和其他新增的异常语句
throw的介绍------throw已被废弃
throw在solidity会被编译成invalid opcode,因此执行到这里,EVM会终止tx(交易)且没收所有的gas
Throrw算是一个误用,实际上solidity并没有错误处理的catch机制。因为它在语言上不算好词
官方建议修改用revert()代替
try...catch介绍
我们在当前合约发起对外部合约调用的话,如果外部合约调用执行失败被 revert,外部合约状态会被回滚,当前合约状态也会被回滚。
但有时候我们并不想这样,要是能够捕获外部合约调用异常,然后根据情况做自己的处理不是更好吗?所以,这种场景下适应于使用 try...catch 语句。
和require对比
以下代码将会触发 catch Error(string memory reason) ,最终输出 require error。
pragma solidity ^0.8.0; contract Manager {function count() public pure returns(int){require(1==2,"require error");return 2;}function test() public view returns(string memory) {try this.count() {return "success";} catch Error(string memory reason/* 出错原因 */) {// 调用 count() 失败时执行,通常是不满足 require 语句条件或触发 revert 语句时所引起的调用失败return reason;} catch (bytes memory) {// 调用 count() 异常时执行,通常是触发 assert 语句或除 0 等比较严重错误时会执行return "assert error";}} }
和assert()对比
以下代码将会触发 catch (bytes memory) ,最终输出 assert error。
pragma solidity ^0.8.0; contract Manager {function count() public pure returns(int){assert(1==2);return 2;}function test() public view returns(string memory) {try this.count() {return "success";} catch Error(string memory reason/* 出错原因 */) {// 调用 count() 失败时执行,通常是不满足 require 语句条件或触发 revert 语句时所引起的调用失败return reason;} catch (bytes memory) {// 调用 count() 异常时执行,通常是触发 assert 语句或除 0 等比较严重错误时会执行return "assert error";}} }
五、Solidity 工厂合约
Solidity 工厂合约是一种批量部署合约的方式。
通过一个工厂合约创建部署合约,并记录下所有部署合约的地址。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;contract Account {address public bank;address public owner;constructor(address _owner) payable{bank = msg.sender;owner = _owner;}
}contract Factory {Account[] public accounts;function createAccount(address owner) external payable{accounts.push(new Account{value:123}(owner));accounts.push(new Account{value:456}(owner));}
}
我们只需要部署 Factory 合约,运行 createAccount 方法,就会自动创建其它合约。
相关文章:

Solidity基础六
生活本来就是平凡琐碎的,哪有那么多惊天动地的大事,快乐的秘诀就是不管对大事小事都要保持热情 目录 一、Solidity的特殊变量(全局) 二、Solidity的不可变量 immutable的赋值方式 三、Solidity的事件与日志 事件和日志加深理解 四、Solidity的异常…...

自学网络安全解决问题方法
自学网络安全很容易学着学着就迷茫了,找到源头问题,解决它就可以了,所以首先咱们聊聊,学习网络安全方向通常会有哪些问题,看到后面有惊喜哦 1、打基础时间太长 学基础花费很长时间,光语言都有几门…...
Java之旅(七)
Java 异常 Java异常(Exception)是在程序运行过程中出现错误或异常情况时,由程序自动抛出,导致程序无法正常运行,用于向上层调用程序传递错误信息或中断程序执行的一种机制。 异常与错误不同,错误是由于程…...
测试报告模板二
项目名称 系统测试报告 平台测试小组 2023年x月xx日 文档信息 文档名称: 作者:...
C语句概述
1 、 C 语句分类: ①控制语句:二个分支语句( if-else 、 switch ),三个循环语句( for 、 while 、 do - while ),四个转移语句( continue 、 break 、 goto 、 return…...

C++ [STL之vector模拟实现]
本文已收录至《C语言和高级数据结构》专栏! 作者:ARMCSKGT STL之vector模拟实现 前言正文空间结构默认成员函数构造函数拷贝构造函数赋值重载析构函数关于数据拷贝问题 迭代器容量操作查询容量容量操作 数据访问下标访问头尾数据访问 数据增删尾插尾删重…...

【算法竞赛进阶指南】141.周期 题解 KMP 最小循环节
题目描述 一个字符串的前缀是从第一个字符开始的连续若干个字符,例如 abaab 共有 5 5 5 个前缀,分别是 a,ab,aba,abaa,abaab。 我们希望知道一个 N N N 位字符串 S S S 的前缀是否具有循环节。 换言之…...
【Springboot 入门培训 】#19 Spring Boot 组件扫描与bean生命周期
目录 1 什么是组件扫描2 何时使用组件扫描3 扫描整个包basePackages与 includeFilters4 Spring boot 的 Bean 生命周期4.1 生命周期4.2 Bean 生命周期4.3 周期各个阶段 首先,我想先为你介绍一下“Spring”,这是一个开放源代码的设计模式解决方案和轻量级…...
Linux printf 函数输出问题
printf 函数并不会直接将数据输出到屏幕,而是先放到缓冲区中,只有一下三种情况满足,才会输出到屏幕。 1) 缓冲区满 2) 强制刷新缓冲区 fflush 3) 程序结束时 1 #include<stdio.h>2 #include<st…...

皮卡丘Unsafe Fileupload
1.不安全的文件上传漏洞概述 文件上传功能在web应用系统很常见,比如很多网站注册的时候需要上传头像、上传附件等等。当用户点击上传按钮后,后台会对上传的文件进行判断 比如是否是指定的类型、后缀名、大小等等,然后将其按照设计的格式进行…...

最优化简明版(上)
引言 本文简单地介绍一些凸优化(Convex Optimization)的基础知识,可能不会有很多证明推导,目的是能快速应用到机器学习问题上。 凸集 直线与线段 设 x 1 ≠ x 2 x_1 \neq x_2 x1x2为 R n \Bbb R^n Rn空间中的两个点,那么具有下列形…...
MySQL的一些介绍
1. SQL的select语句完整的执行顺序 SQL Select语句完整的执行顺序: 1、from子句组装来自不同数据源的数据; 2、where子句基于指定的条件对记录行进行筛选; 3、group by子句将数据划分为多个分组; 4、使用聚集函数进行计算&am…...

unity发布webGL后无法预览解决
众所周知,unity发布成webgl后是无法直接预览的。因为一般来说浏览器默认都是禁止webgl运行的。 直接说我最后的解决方法:去vscode里下载一个live server ,安装好。 下载vscode地址Visual Studio Code - Code Editing. Redefined 期间试过几种方法都不管…...

Flume和Kafka的组合使用
一.安装Kafka 1.1下载安装包 通过百度网盘分享的文件:复制链接打开「百度网盘APP 即可获取」 链接:https://pan.baidu.com/s/1vC6Di3Pml6k1KMbnK0OE1Q?pwdhuan 提取码:huan 也可以访问官网,下载kafka2.4.0的安装文件 1.2解…...

JSONSQL:使用SQL过滤JSON类型数据(支持多种数据库常用查询、统计、平均值、最大值、最小值、求和语法)...
1. 简介 在开发中,经常需要根据条件过滤大批量的JSON类型数据。如果仅需要过滤这一种类型,将JSON转为List后过滤即可;如果相同的条件既想过滤数据库表中的数据、也想过滤内存中JSON数据,甚至想过滤Elasticsearch中的数据ÿ…...

Linux输入输出重定向
目录 Linux输入输出重定向 Linux中的默认设备 输入输出重定向定义 输入输出重定向操作符 实用形式 标准输入、标准输出、标准错误 输出重定向案例 案例1 --- 输出重定向(覆盖) 案例2 --- 输出重定向(追加) 案例3 --- 错误…...

使用kettle进行数据统计
1.使用kettle设计一个能生成100个取值范围为0到100随机整数的转换。 为了完成该转换,需要使用生成记录控件、生成随机数控件、计算器控件及字段选择控件。控件布局如下图所示 生成记录控件可以在限制框内指定生成记录的个数,具体配置如图所示 生成随机数…...
线程的取消和清理
一、线程的取消 意义:随时杀掉一个线程 int pthread_cancel(pthread_t thread); 注意:线程的取消要有取消点才可以,不是说取消就取消,线程的取消点主要是阻塞的系统调用 二、运行段错误调试 可以使用gdb调试 使用gdb 运行代…...

day8 -- 全文本搜索
brief InnoDB存储引擎从MySQL 5.6开始支持全文本搜索。具体来说,MySQL使用InnoDB存储引擎的全文本搜索功能称为InnoDB全文本搜索(InnoDB Full-Text Search)。InnoDB全文本搜索支持标准的全文本搜索查询语法和多语言分词器,因此可…...
C语言:if-else语句
嗨,今天咱们讲讲C语言控制语句里的条件选择,主要总结下if else语句。 咱们生活里经常会有这样的场景,明天该怎么穿呢,得考虑下具体的天气。如果是晴天,温度还不错,可以穿T恤;如果是阴天…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...