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恤;如果是阴天…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...

JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...

海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》
近日,嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》,海云安高敏捷信创白盒(SCAP)成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天,网络安全已成为企业生存与发展的核心基石,为了解…...

【工具教程】多个条形码识别用条码内容对图片重命名,批量PDF条形码识别后用条码内容批量改名,使用教程及注意事项
一、条形码识别改名使用教程 打开软件并选择处理模式:打开软件后,根据要处理的文件类型,选择 “图片识别模式” 或 “PDF 识别模式”。如果是处理包含条形码的 PDF 文件,就选择 “PDF 识别模式”;若是处理图片文件&…...

【汇编逆向系列】六、函数调用包含多个参数之多个整型-参数压栈顺序,rcx,rdx,r8,r9寄存器
从本章节开始,进入到函数有多个参数的情况,前面几个章节中介绍了整型和浮点型使用了不同的寄存器在进行函数传参,ECX是整型的第一个参数的寄存器,那么多个参数的情况下函数如何传参,下面展开介绍参数为整型时候的几种情…...