news 2026/10/25 1:19:06

Solidity学习笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Solidity学习笔记

以太坊

共识协议有

  • pow(工作量证明)
  • pos(权益证明)

结点类型有

  • 普通节点:备份区块链数据
  • 矿工:创建区块链

加密算法使用的是ECC(椭圆曲线加密算法)
通信协议使用的是Whisper
存储平台使用的是Swarm
geth是以太坊,whipster和swarm节点的一个实现

帐户类型有

  • 外部帐户
  • 合约帐户

帐户结构有

  • nonce:外部帐户表示从该帐户地址发送出的交易数量,合约帐户表示该帐户创建过的合约数量
  • balance:帐户余额,以wei为单位
  • storageRoot:该帐户存储内容的Merkle Patricia树的根结点哈希值
  • codeHash:外部帐户是空字符串的哈希值,合约帐䚮是该帐户的EVM code(编译后的智能合约字节码)的哈希值

solidity流程

Solidity代码

Solidity编译器

字节码

部署在EVM上执行

文件组成

Solidity文件,扩展名为.sol,由4个结构组成

  • 预编译指令
  • 注释
  • 导入
  • 合约/库/接口

使用下面指令指定编译器版本

pragma Solidity<version number>

版本声明^0.5.2表示兼容0.5.2以及向后兼容的补丁版本,但不包括 0.6.0 及以上版本
注释形式有

  • 单行注释 :用双斜线表示//
  • 多行注释 :用/*和*/表示
  • 以太坊自然规范:即三个斜杠///表示单行注释,多行注释用/**表示注释开始,*/表示注释结束

导入其它合约使用

import"otherContract";//导入所有的全局符号import*as symbolName from"filename";//导入filename所有的全局符号作为全局符号名symbolName的成员import{symbol1 as alias,symbol2}from"filename";

合约使用关键字contract,库使用关键字library,接口使用关键字interface

合约

合约结构包含

  • 状态变量
  • 结构定义:使用struct
  • 修改器定义:使用关键字modifier,修改器与函数绑定。修改器中的下划线_表示执行目标函数。payable是由Solidity提供的修改器,当应用于函数时允许函数接受以太币
  • 事件声明:使用关键字event来定义
  • 枚举定义
  • 函数定义:函数支持的限定符有external, payable(k只能接受以太币), view(常量函数别名),pure(既不能读取也不能写入,不能访问状态变量),其修饰符默认是public

状态变量

定义形式为<类型 修饰符 标识符>
修饰符有

  • internal:在没有显示指定情况下,默认是internal
  • private
  • public:对于此类型,会生成public的获取函数
  • constant

对于address public miner生成的函数形式为

functionminter()external view returns(address){returnminter;}

数据类型支持的有

  • bool
  • uint/int:从8位到256位,没有指定位数时,表示的是256位
  • bytes
  • address
  • mapping:mapping(KeyType KeyName? => ValueType ValueName?) VariableName
  • enum
  • struct
  • string

事件

关键字为event,形式为

eventSent(address from,address to,uint amount);

函数

其定义为

functionFunctionName([parameters]){public|private|internal|external}[pure|constant|view|payable][virtual][modifiers][returns(returntypes)]

函数可见性有

  • public
  • private
  • internal
  • external

函数读写性有

  • view
  • constant:0.5.0版本后丢弃
  • pure

合约创建

有两种方式

  • 使用new创建
contract Helloworld{}contract client{functioncreateHelloworld()public returns(Helloworld address){returnnewHelloworld()}}
  • 使用已经部署的合约地址
contract client{functionuseHelloworld(address addr)public{Helloworld hw=Helloworld(addr)}}

构造函数

在用new创建合约时,会调用构造函数。构造函数只会调用一次,也只能有一个构造函数,不能重载。

contract Helloworld{construct([参数]){}}

继承

单继承:使用形式为子合约 is 父合约
多继承:使用形式为子合约 is 父合约1,父合约2,...
在调用继承体系中的函数时,可以直接使用父合约.函数,直接调用其直接父合约使用super.函数(在多继承中时,按照父合约声明顺序调用)
需要重载的函数使用virtual修饰符,子合约重载父合约函数使用override修饰符
重载时支持修改函数的可见性(从不严格转为严格的,不能从严格的转不严格的)有

  • external转public
  • nonpayable转view和pure
  • view转pure
  • payable不能转

修改器跟函数一样支持重载,也是使用virtual和override
对于有参数的构造函数,有两种方式

  • 直接在继承声明时指定父合约的参数
  • 在子合约构造函数中,显示指定父合约参数

否则只能将合约声明为抽象的

抽象合约

合约前使用abstract,即合约中函数没有实现

接口

关键字为interface,约束有

  • 不能包含实现的函数
  • 不能继承合约,可以继承其它接口
  • 所有函数必须是external
  • 不能声明构造函数
  • 不能声明状态变量
  • 不能声明修改器

特殊函数

  • receive函数
receive()external payable{...}
  • fallback函数
fallback()external[payable]fallback(bytes calldata input)external[payable]

数据类型


值类型有

  • bool
  • uint/int
  • address:分为payable(包含transfer和send)和不能支付的,
  • byte:是bytes1的别名,字节类型还支持1-32,即bytes1-bytes32
  • enum
  • 定长浮点型:fixed和ufixedMxN,其中M表示所占的大小,需要为8的位数,范围为8-256,N表示小数点的位数,范围为0-80
  • 定长数组:即固定数组int[5] age
  • 函数类型:对于external和public函数,其包含两个属性.address(合约地址)和.selector(abi函数选择器)
  • 用户自定义值类型:如type aliasName as built-in-type
  • 合约类型:可以与地址作相互转换

引用类型有

  • 动态数组:int[] age。动态数组可以使用内联初始化或者使用new运算符初始化,内联形式为int[] age = [1, 2,3],new初始化形式为int[] age = new int[](5)。solidity中有特殊数组类型,即字节数组bytes和字符串数组string。T[M][N] 表示 N 个长度为 M 的数组(外层长度是 N)
  • 数组切片
  • 结构
  • 映射

type函数

type(C).name:合约名称
type(C).creationCode:合约的创建字节码
type(C).runtimeCode:合约的运行字节码
type(I).interfaceId:一个 bytes4 值,包含给定接口 I 的 EIP-165 接口标识符
type(T).min:类型T的最小值
type(T).max:类型T的最大值

错误处理

require:检查输入
assert:检查结果

字面量

字符串字面量用单引号或者双引号
十六进制字面量以前缀hex作为关键字,如hex "1A2B3F"

全局变量和函数

区块

blockhash(uint blockNumber) returns (bytes32):当 blockNumber是 256 个最新区块之一时,给定区块的哈希值;否则返回零
blobhash(uint index) returns (bytes32):与当前事务关联的索引第index个 Blob 的版本化哈希。版本化哈希由代表版本(当前0x01)的单个字节组成,后跟 KZG 承诺 (EIP-4844) 的 SHA256 哈希的最后 31 个字节。如果不存在具有给定索引的 blob,则返回零。
block.basefee (uint):当前区块的基本费用(EIP-3198 和 EIP-1559)
block.blobbasefee (uint):当前区块的 blob 基本费用(EIP-7516 和 EIP-4844)
block.chainid (uint):当前链 ID
block.coinbase (address payable):当前区块矿工地址
block.difficulty (uint):当前区块难度(EVM < Paris)
block.prevrandao (uint):信标链提供的随机数 (EVM >= Paris)
block.gaslimit (uint):当前块 gas限制
block.number (uint):当前区块编号
block.timestamp (uint):当前区块时间戳(自 Unix 纪元以来的秒数)

消息

msg.data (bytes calldata):完整的调用数据,与创建交易相关的函数及其参数信息
msg.sender (address):调用函数的地址
msg.sig (bytes4):函数标识符使用散列函数签名后的前四个字节
msg.value (uint):随消息发送的以太币数量,以wei为单位

交易

tx.gasprice (uint):交易的 gas 价格
tx.origin (address):交易的发送者(全调用链)

加密

keccak256(bytes memory) returns (bytes32):计算输入的 Keccak-256 哈希值,其基于SH3算法
sha256(bytes memory) returns (bytes32):计算输入的 SHA-256哈希值,基基于SH2算法

地址

<address>.balance (uint256):是address类型的内置全局变量,用于查询某个地址的ETH余额,单位为wei
全局函数有

  • <address payable>.transfer(uint256 amount):安全转换函数,向目标地址发送指定数量的ETH,若转帐失败,自动回滚当前交易。要求目标地址是address payable类型
  • <address payable>.send(uint256 amount) returns (bool):低级转账函数,但是转账失败,不会自动 回滚
  • <address>.call(bytes memory) returns (bool, bytes memory):通用低级调用函数,向目标地址发送一个自定义数据的调用请求,地址要求是 EOA或者合约地址( 定义了payable 的 fallback 函数的)
  • <address>.delegatecall(bytes memory) returns (bool, bytes memory):委托调用函数,与call类似,但是使用当前合约的上下文
  • <address>.staticcall(bytes memory) returns (bool, bytes memory):只读调用函数,禁止修改任何状态

合约

合约全局变量有

  • this:表示当前合约的类型,可以显示转换成地址address contractAddress = address(this);

合约全局函数有

  • selfdestruct(address payable recipient):销毁当前合约,并且把剩余的以太币余额转移到参数指定地址

库

库里的内部函数是以复制的形式到调用它的合约中,内部类型可以传递,内存类型以引用传递
有以下限制

  • 无状态变量
  • 不能继承和被继承
  • 不能接收以太币
  • 不能销毁一个库

使用场景

  • 节省gas
  • 给数据类型添加成员函数

主要是代码复用
using A for B:表示给自定义类型B添加库A中的操作符,相当于B的成员函数,其中A函数的第一参数相当于python中的self

ABI

有两种形式,一种是参数二进制编码,一种是json形式

参数编码(二进制形式)

首先是4字节的函数签名,然后是对函数参数的编码
对于静态类型和动态类型的编码方式不一样,动态类型有

  • string
  • bytes
  • 定长数组
  • 变长数组
  • 元组(T1,…,Tk)

元组编码形式为
enc(X) = head(X(1)) … head(X(k)) tail(X(1)) … tail(X(k))
对于静态类型,head(X(i)) = enc(X(i)), tail(X(i)) = “”
对于动态类型,head(X(i)) = enc(len( head(X(1)) … head(X(k)) tail(X(1)) …tail(X(i-1)) )), tail(X(i)) = enc(X(i))

json形式

json形式主要函数、事件或者error的数组形式

函数

json字段有

  • type:其支持的值有function,constructor, receive,fallback
  • name:表示函数名称
  • inputs:对象数组,其包含以下字段
    • name:参数名
    • type:参数的规范类型
    • components:用于元组类型
  • outputs:与inputs类似,为对象数组
  • stateMutability:支持的值有pure,view,nonpayable和payable

constructor, receive,fallback不会有name和ouputs字段,receive,fallback不会有inputs字段

事件

json字段有

  • type:值为event
  • name:表示事件名
  • inputs:对象数组,其包含以下字段
    • name:参数名
    • type:参数的规范类型
    • components:用于元组类型
    • indexed:布尔值,如果该字段是日志主题的一部分则为true,否则为false
  • anonymous:布尔值,如果事件声明为anonymous则为true

error

json字段有

  • type:值为error
  • name:表示错误名
  • inputs:对象数组,其包含以下字段
    • name:参数名
    • type:参数的规范类型
    • components:用于元组类型

EVM虚拟机

数据存储位置

类型说明
Storage(存储)局部复杂类型变量和状态变量默认存储位置是存储
Transient Storage(暂存)与Storage区别是每次交易后会复位
Memory(内存)函数参数包含返回值默认存储位置是内存
Stack(栈)EVM是基于栈的虚拟机,所有计算是基于栈执行的
Calldata(调用数据)即发给交易的数据。在创建合约时,calldata将是新合约的构造函数代码;abi编码形式外部函数的参数
returndata(返回数据)合约调用后的返回值赋值给abi编码的值
code(代码)合约存储的位置
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/25 1:15:46

浏览器 GEMM 先算对布局:WGSL、limits 与非整 tile 验收

矩阵乘法的性能表很容易写得漂亮&#xff0c;最难看出来的错误却可能只有一个&#xff1a;CPU 按行存数据&#xff0c;着色器按另一种步长读取。 先别比 M 系列和 RTX。拿一个非方阵、边缘不满块的输入&#xff0c;把布局与边界验收做完。本文只讨论浏览器里的 JS/WGSL 数据合…

作者头像 李华
网站建设 2026/10/25 1:15:13

子网路由器与出口节点:Headscale Routes配置完全指南

子网路由器与出口节点&#xff1a;Headscale Routes配置完全指南 Headscale 是开源的 Tailscale 控制服务器自托管实现&#xff0c;其中 Routes&#xff08;路由&#xff09;功能可以让你轻松配置子网路由器&#xff08;Subnet Router&#xff09;与出口节点&#xff08;Exit …

作者头像 李华
网站建设 2026/10/25 1:13:07

STM32型号验证与CMake+VSCode嵌入式开发实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/25 1:13:06

Fast-DDS深度解析:从DDS原理到通信调优与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/25 1:11:28

ESP32系列一键烧录包制作指南:从esptool合成到交付避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华