【区块链安全 | 第十四篇】类型之值类型(一)

文章目录

  • 值类型
    • 布尔值
    • 整数
      • 运算符
      • 取模运算
      • 指数运算
    • 定点数
    • 地址(Address)
      • 类型转换
      • 地址成员
        • balance 和 transfer
        • send
        • call,delegatecall 和 staticcall
        • code 和 codehash
    • 合约类型(Contract Types)
    • 固定大小字节数组(Fixed-size byte arrays)
    • 地址字面量(Address Literals)

在这里插入图片描述

Solidity 是一种静态类型语言,这意味着每个变量(无论是状态变量还是局部变量)都需要指定其类型。Solidity 提供了几种基本类型,这些类型可以组合形成复杂类型。

此外,不同类型可以在包含运算符的表达式中相互作用,并且具有优先级的区分。

Solidity 没有“未定义”或“空”值的概念,但新声明的变量总是具有默认值,该默认值取决于其类型。为了处理任何意外的值,应该使用 revert 函数回滚整个交易,或者返回一个带有布尔值的元组,其中第二个 bool 值表示操作是否成功。

值类型

值类型的变量始终按值传递,即在作为函数参数或赋值时总是被复制。

与引用类型不同,值类型的声明不指定数据位置,因为它们足够小,可以存储在栈中。唯一的例外是状态变量,状态变量默认存储在存储中,但也可以标记为 transient、constant 或 immutable。

布尔值

bool:值是 truefalse

整数

int / uint:各种大小的有符号和无符号整数。

关键字 uint8uint256(以 8 为步长,表示 8 位到 256 位的无符号整数),以及 int8int256

uintint 分别是 uint256int256 的别名。

运算符

比较运算符:<=<==!=>=>(结果为 bool

位运算符:&|^(按位异或),~(按位取反)

移位运算符:<<(左移),>>(右移)

算术运算符:+-,一元 -(仅适用于有符号整数),*/%(取模),**(指数运算)

对于整数类型 X,可以使用 type(X).mintype(X).max 来访问该类型可表示的最小值和最大值。

运算符 ||&& 遵循短路规则。这意味着在表达式 f(x) || g(y) 中,如果 f(x) 计算结果为 true,则 g(y) 将不会被计算。

注意
Solidity 中的整数受到特定范围的限制。例如,对于 uint32,其范围为 02**32 - 1

在 Solidity 中,整数运算有两种模式:“溢出”模式(wrapping/unchecked mode)“检查”模式(checked mode)

默认情况下,运算始终处于 “检查”模式,这意味着如果运算结果超出了类型的值范围,则调用会因失败的断言而回滚。

可以使用 unchecked { ... } 切换到 “溢出”模式,但应谨慎使用。

取模运算

% 的结果是操作数 a 除以操作数 n 后的余数 r,其中 q = int(a / n),并且 r = a - (n * q)

这意味着取模运算的结果与其左操作数的符号相同(或为零),并且对于负数 aa % n == -(-a % n) 恒成立:

int256(5) % int256(2) == int256(1)int256(5) % int256(-2) == int256(1)int256(-5) % int256(2) == int256(-1)int256(-5) % int256(-2) == int256(-1)

注意:使用 0 作为取模运算的除数会导致 Panic 错误。此检查无法通过 unchecked { ... } 关闭。

指数运算

指数运算 ** 仅适用于无符号类型作为指数(幂)。指数运算的结果类型始终与底数的类型相同。请确保底数足够大以容纳结果,并预防潜在的断言失败或溢出行为。

注意:在 检查模式(checked mode)下,对于较小的底数,指数运算仅使用相对廉价的 EXP 操作码。

例如,在计算 x**3 时,使用 x*x*x 可能更便宜。因此,建议进行 Gas 成本测试 并使用优化器。此外,EVM 规定 0**0 的结果为 1

定点数

警告:定点数在 Solidity 中尚不完全支持。它们可以被声明,但不能进行赋值操作。

fixed / ufixed:带符号和无符号定点数,具有不同的大小。关键字 ufixedMxNfixedMxN,其中 M 代表类型所占用的位数,N 代表可用的小数位数。M 必须是 8 的倍数,范围从 8 到 256 位。N 必须在 0 到 80 之间(包含 0 和 80)。ufixedfixedufixed128x18fixed128x18 的别名。

操作符

  • 比较操作符:<=<==!=>=>(结果为布尔值)

  • 算术操作符:+-,一元 -(仅对带符号数),*/%(取模)

注意:浮动点数(许多语言中的 floatdouble,更精确地说是 IEEE 754 数字)和定点数的主要区别在于,浮动点数用于表示整数和小数部分的位数是灵活的,而定点数则严格定义了每部分所占的位数。通常,在浮动点数中,几乎整个空间用于表示数字,而只有少数位数用于定义小数点的位置。

地址(Address)

地址类型有两种主要相似的变体:

  • address:持有一个 20 字节的值(以太坊地址的大小)。
  • address payable:与 address 相同,但具有额外的 transfersend 成员。

这种区分的想法是,address payable 是一个可以接收以太币的地址,而普通的 address 不能接收以太币,例如,它可能是一个不支持接收以太币的智能合约。

类型转换

1.允许从 address payableaddress 的隐式转换,而从 addressaddress payable 必须通过显式转换 payable(<address>)
2.允许显式转换到 address 类型并返回 uint160、整数字面量、bytes20 和合约类型。
3.只有 address 类型和合约类型的表达式可以通过显式转换 payable(...) 转换为 address payable。对于合约类型,只有在合约可以接收以太币的情况下(即合约有 receivepayable 回退函数)才能进行这种转换。注意,payable(0) 是有效的,且是这一规则的例外。

注意
如果我们需要一个 address 类型的变量,并计划向其发送以太币,那么应将其声明为 address payable 以使该要求更加明显。此外,尽量在最早阶段做出这种区分或转换。

从 0.5.0 版本开始,addressaddress payable 之间的区分被引入。自那时起,合约不能隐式转换为 address 类型,但如果它们有 receivepayable 回退函数,仍然可以显式地转换为 addressaddress payable

地址成员

balance 和 transfer

可以使用 balance 属性查询地址的余额,并使用 transfer 函数将以太币(以 wei 为单位)发送到可支付的地址:

address payable x = payable(0x123);
address myAddress = address(this);
if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10);

transfer 函数在当前合约的余额不足或接收方帐户拒绝接收以太币时失败,并会回滚操作。

注意
如果 x 是一个合约地址,它的代码(更具体地说:其 Receive Ether 函数如果存在,或其他回退函数如果存在)将在 transfer 调用时一起执行,这是 EVM 的特性,无法阻止。如果该执行耗尽了 gas 或以任何方式失败,Ether 转账将回滚,当前合约将停止并抛出异常。

send

sendtransfer 的低级对等函数。如果执行失败,当前合约不会停止并抛出异常,而是返回 false

使用 send 时存在一些危险:如果调用堆栈深度达到 1024(调用者可以强制此情况),或者接收方耗尽 gas,则转账将失败。因此,为了安全地转账以太币,始终检查 send 的返回值,使用 transfer 或更好的方式是使用一个模式,其中接收方自己提取以太币。

call,delegatecall 和 staticcall

为了与不符合 ABI 的合约交互,或为了更直接地控制编码,可以使用 calldelegatecallstaticcall 函数。它们都接受一个字节内存参数,并返回成功条件(布尔值)和返回的数据(字节内存)。abi.encodeabi.encodePackedabi.encodeWithSelectorabi.encodeWithSignature 可以用来编码结构化数据。

示例:

bytes memory payload = abi.encodeWithSignature("register(string)", "MyName");
(bool success, bytes memory returnData) = address(nameReg).call(payload);
require(success);

注意,这些都是低级函数,应该小心使用。特别是,任何未知的合约可能是恶意的,如果调用它,你将把控制权交给该合约,而该合约可能会再次调用你的合约,因此当调用返回时,需要做好准备处理可能会更改的状态变量。与其他合约交互的常规方式是调用合约对象上的函数(例如 x.f())。

可以使用 gas 修饰符调整提供的 gas:

address(nameReg).call{gas: 1000000}(abi.encodeWithSignature("register(string)", "MyName"));

类似地,也可以控制提供的 Ether 数量:

address(nameReg).call{value: 1 ether}(abi.encodeWithSignature("register(string)", "MyName"));

最后,这些修饰符可以结合使用,它们的顺序无关紧要:

address(nameReg).call{gas: 1000000, value: 1 ether}(abi.encodeWithSignature("register(string)", "MyName"));

类似地,可以使用 delegatecall 函数,不同之处在于,只有给定地址的代码会被使用,所有其他方面(存储、余额等)都来自当前合约。delegatecall 的目的是使用存储在另一个合约中的库代码。用户必须确保两个合约的存储布局适合使用 delegatecall

code 和 codehash

你可以查询任何智能合约的已部署代码。使用 .code 获取 EVM 字节码作为字节内存(可能为空)。使用 .codehash 获取该代码的 Keccak-256 哈希(作为 bytes32)。注意,addr.codehash 比使用 keccak256(addr.code) 更便宜。

如果与 addr 相关联的帐户为空或不存在(即它没有代码、零余额和零 nonce,如 EIP-161 所定义),则 addr.codehash 的输出可能为 0。如果该帐户没有代码,但有非零余额或 nonce,则 addr.codehash 将输出空数据的 Keccak-256 哈希(即 keccak256(""),其结果为 c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470)。

注意,所有合约都可以转换为 address 类型,因此可以使用 address(this).balance 查询当前合约的余额。

合约类型(Contract Types)

每个合约都定义了自己的类型。你可以将合约隐式转换为它继承的合约类型。合约类型可以显式地转换为 address 类型,反之亦然。

显式转换到 address payable 类型仅在合约类型有 receivepayable 回退函数时才可能。转换仍然通过 address(x) 进行。如果合约类型没有 receivepayable 回退函数,可以使用 payable(address(x)) 进行转换。

注意
1.如果你声明一个合约类型的局部变量(例如 MyContract c),你可以在该合约上调用函数。需要注意的是,必须从与之相同的合约类型赋值给该变量。
2.你也可以实例化合约(这意味着它们是新创建的)。你可以在“通过 new 创建合约”部分找到更多的细节。
3.合约的数据显示方式与 address 类型相同,并且这种类型也用于 ABI 中。
4.合约不支持任何操作符。
5.合约类型的成员是该合约的外部函数,包括任何标记为 public 的状态变量。
6.对于合约 C,你可以使用 type(C) 来访问有关该合约的类型信息。

固定大小字节数组(Fixed-size byte arrays)

值类型 bytes1, bytes2, bytes3, …, bytes32 用于存储从 1 到 32 字节的字节序列。

操作符:

  • 比较操作符:<=, <, ==, !=, >=, >(返回布尔值)
  • 位操作符:&, |, ^(按位异或),~(按位取反)
  • 移位操作符:<<(左移),>>(右移)
  • 索引访问:如果 x 是类型 bytesI,则 x[k](0 <= k < I)返回第 k 个字节(只读)。

移位操作符与无符号整数类型作为右操作数一起工作(但返回左操作数的类型),表示要移位的位数。使用有符号类型进行移位会导致编译错误。

成员.length 可以返回字节数组的固定长度(只读)。

注意
类型 bytes1[] 是字节的数组,但由于填充规则,对于每个元素,它浪费 31 字节的空间(在存储中除外)。最好使用 bytes 类型。

地址字面量(Address Literals)

地址字面量是通过地址校验和测试的十六进制字面量,例如 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AFaddress 类型。长度在 39 到 41 位之间且未通过校验和测试的十六进制字面量会产生错误。

我们可以通过在前面(对于整数类型)或后面(对于 bytesNN 类型)加零来去除错误。

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

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

相关文章

Windows 系统下多功能免费 PDF 编辑工具详解

IceCream PDF Editor是一款极为实用且操作简便的PDF文件编辑工具&#xff0c;它完美适配Windows操作系统。其用户界面设计得十分直观&#xff0c;哪怕是初次接触的用户也能快速上手。更为重要的是&#xff0c;该软件具备丰富多样的强大功能&#xff0c;能全方位满足各类PDF编辑…

【算法day28】解数独——编写一个程序,通过填充空格来解决数独问题

37. 解数独 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参考示例图&#xff…

力扣刷题-热题100题-第29题(c++、python)

19. 删除链表的倒数第 N 个结点 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/?envTypestudy-plan-v2&envIdtop-100-liked 计算链表长度 对于链表&#xff0c;难的就是不知道有多少元素&#xff…

【QT】QT的多界面跳转以及界面之间传递参数

QT的多界面跳转以及界面之间传递参数 一、在QT工程中添加新的界面二、多界面跳转的两种情况1、A界面跳到B界面&#xff0c;不需要返回2、A界面跳到B界面&#xff0c;需要返回1&#xff09;使用this指针传递将当前界面地址传递给下一界面2&#xff09;使用parentWidget函数获取上…

【力扣hot100题】(022)反转链表

非常经典&#xff0c;我写的比较复杂&#xff0c;一直以来的思路都是这样&#xff0c;就没有去找更简单的解法&#xff1a;&#xff08;做链表题习惯加头结点的前置节点了&#xff0c;去掉也行&#xff09; /*** Definition for singly-linked list.* struct ListNode {* …

剑指Offer(数据结构与算法面试题精讲)C++版——day2

剑指Offer(数据结构与算法面试题精讲)C++版——day2 题目一:只出现一次的数据题目二:单词长度的最大乘积题目三:排序数组中的两个数字之和题目一:只出现一次的数据 一种很简单的思路是,使用数组存储出现过的元素,比如如果0出现过,那么arr[0]=1,但是有个问题,题目中没…

技术回顾day2

1.获取文件列表 流程&#xff1a;前端根据查询条件封装查询信息&#xff0c;后端接收后进行封装&#xff0c;封装为FileInfoQuery,根据fileInfoQuery使用mybatis的动态sql来进行查询。 2.文件分片上传 每次上传需要上传包括(文件名字&#xff0c;文件&#xff0c;md5值&#…

DeepSeek-R1 模型现已在亚马逊云科技上提供

2025年3月10日更新—DeepSeek-R1现已作为完全托管的无服务器模型在Amazon Bedrock上提供。 2025年2月5日更新—DeepSeek-R1 Distill Llama 和 Qwen模型现已在Amazon Bedrock Marketplace和Amazon SageMaker JumpStart中提供。 在最近的Amazon re:Invent大会上&#xff0c;亚马…

STP --- 生成树协议

协议信息 配置 BPDU Protocol identifier&#xff1a;协议标识 Version&#xff1a;协议版本&#xff1a;STP 为 0&#xff0c;RSTP 为 2&#xff0c;MSTP 为 3 type&#xff1a; BPDU 类型 Flag&#xff1a; 标志位 Root ID&#xff1a; 根桥 ID&#xff0c;由两字节的优…

Ansible playbook-ansible剧本

一.playbook介绍 便于功能的重复使用 本质上就是文本文件&#xff0c;一般都是以.yml结尾的文本文件。 1.遵循YAML语法 1.要求同级别代码要有相同缩进&#xff0c;建议4个空格。【同级别代码是同一逻辑的代码】 在计算机看来空格和Tob键是两个不同的字符。 2.一个键对应一…

python的基础入门

初识Python 什么是Python Python是1门程序设计语言。在开发者眼里&#xff0c;语言可以分为3类&#xff1a; 自然语言&#xff1a;人能听懂的语言&#xff0c;例如汉语&#xff0c;英语&#xff0c;法语等等。机器语言&#xff1a;机器能听懂的语言&#xff0c;机器只能听懂0…

8.neo4j图数据库python操作

使用图数据库的原因 图数据库使用neo4j的原因&#xff1a;neo4j使用率高&#xff0c;模板好找&#xff0c;报错能查。 红楼梦人物关系图地址 GraphNavigator neo4j学习手册 https://www.w3cschool.cn/neo4j/neo4j_need_for_graph_databses.html CQL代表的是Cypher查询语言…

[Lc6_记忆化搜索] 扫雷游戏 | 理解 递归vs记忆化搜索vs dp

目录 ⭕1.扫雷游戏 题解 1.记忆化搜索 解法一&#xff1a;递归 解法二&#xff1a;记忆化搜索 解法三&#xff1a;动态规划 ⭕1.扫雷游戏 (暴力模拟&#xff09; 链接&#xff1a;529. 扫雷游戏 让我们一起来玩扫雷游戏&#xff01; 给你一个大小为 m x n 二维字符矩阵…

第十一章:Python PIL库-图像处理

一、PIL库简介 PIL&#xff08;Python Imaging Library&#xff09;是一个功能强大的图像处理库&#xff0c;它提供了丰富的图像处理功能&#xff0c;包括图像的打开、处理和保存等操作。PIL支持多种图像文件格式&#xff0c;如JPEG、PNG、BMP等&#xff0c;并且可以完成对图像…

ISIS报文

IS-IS 报文 目录 IS-IS 报文 一、报文类型与功能 二、报文结构解析 三、核心功能特性 四、典型应用场景 五、抓包数据分析 六、总结 IS-IS&#xff08;中间系统到中间系统&#xff09;协议报文是用于链路状态路由协议中网络设备间交换路由信息的关键载体&#xff0c;其设…

beikeshop多商户跨境电商独立站最新版v1.6.0版本源码

一.介绍 beikeshop跨境电商独立站最新版V1.6.0源码 多商户 多商家 多语言 多币结算 本博主亲测搭建代码全开源质量相对来说很稳定的 二.服务器环境 系统&#xff1a;CentOS、 环境&#xff1a;PHP7.4 Nginx 1.21 MySQL 5.6 常见插件&#xff1a;fileinfo &#xff1b; re…

Spring Boot 集成实战:AI 工具如何自动生成完整微服务模块

在数字化转型的浪潮中&#xff0c;开发效率和质量是企业竞争力的关键要素。飞算 JavaAI 作为一款创新的 AI 工具&#xff0c;能在 Spring Boot 开发中&#xff0c;自动生成完整微服务模块&#xff0c;极大提升开发效率。下面&#xff0c;我们就详细介绍如何借助飞算 JavaAI&…

Vue 组件通信 - 中央事件总线

Vue 渐进式JavaScript 框架 基于Vue2的学习笔记 - Vue组件通信 - 中央事件总线 目录 中央事件总线 图示 准备工作 设置页面元素 创建组件 总结 中央事件总线 使用vue的监听和触发来实现中央事件总线方式。 on监听 emit触发&#xff0c;组件按钮绑定点击事件&#xff0c…

5.0 WPF的基础介绍1-Grid,Stack,button

WPF: Window Presentation Foundation. WPF与WinForms的对比如下&#xff1a; 特性WinFormsWPF技术基础基于传统的GDI&#xff08;图形设备接口&#xff09;基于DirectX&#xff0c;支持硬件加速的矢量渲染UI设计方式拖拽控件事件驱动代码&#xff08;简单但局限&#xff09;…

pytorch学习(b站小土堆学习)

1 环境配置 参考链接 2. dir 和 help函数 dir()&#xff1a;用于查看某一模块函数的方法 help()&#xff1a; 用于查看某方法的使用方法 3. dataset类实战 利用Image对象打开图片&#xff0c;利用os模块的地址拼接组成图片路径 当我们用方括号访问元素对象时&#xff0c;…