前言
写本文的目的是记录自己对于区块链技术的学习,方便日后查漏补缺,solidity是一门智能合约语言,是静态类型语言,支持继承等特性。solidity中不存在 undefine和null的概念,每个新声明的变量都会根据其类型赋予默认值。
一、单位
单位之间的换算就是在数字后边加上wei
,gwei
或ether
来实现的,如果后面没有单位,缺省为 wei。
- 1 wei == 1
- 1 gwei == 1e9 wei
- 1 ether == 1e9 gwei
二、时间单位
秒是缺省时间单位,在时间单位之间,数字后面带有seconds
、minutes
、hours
、days
和weeks
的可以进行换算,基本换算关系如下:
1 == 1 seconds
1 minutes == 60 seconds
1 hours == 60 minutes
1 days == 24 hours
1 weeks == 7 days
years
已经在0.5.0版本去除了,因为闰年的原因。
三、区块和交易属性
blockhash(uint blockNumber) returns (bytes32)
:指定区块的区块哈希 —— 仅可用于最新的 256 个区块且不包括当前区块,否则返回 0 。block.basefee
(uint
): 当前区块的基础费用block.chainid
(uint
): 当前链 idblock.coinbase
(address
): 挖出当前区块的矿工地址block.difficulty
(uint
): 当前区块难度block.gaslimit
(uint
): 当前区块 gas 限额block.number
(uint
): 当前区块号block.timestamp
(uint
): 自 unix epoch 起始当前区块以秒计的时间戳gasleft() returns (uint256)
:剩余的 gasmsg.data
(bytes
): 完整的 calldatamsg.sender
(address
): 消息发送者(当前调用)msg.sig
(bytes4
): calldata 的前 4 字节(也就是函数标识符)msg.value
(uint
): 随消息发送的 wei 的数量tx.gasprice
(uint
): 交易的 gas 价格tx.origin
(address
): 交易发起者(完全的调用链)
对于每一个外部函数调用,包括
msg.sender
和msg.value
在内所有msg
成员的值都会变化。这里包括对库函数的调用。
基于可扩展因素,区块哈希不是对所有区块都有效。你仅仅可以访问最近 256 个区块的哈希,其余的哈希均为零。
blockhash
函数之前是使用block.blockhash
,block.blockhash
在 0.4.22 开始不推荐使用,在 0.5.0 已经移除了。
gasleft
函数之前是使用msg.gas
,msg.gas
在 0.4.21 开始不推荐使用,在 0.5.0 已经移除了。在 0.7.0,
now
(block.timestamp
的别名) 被移除了。
四、错误处理
assert(bool condition)
如果不满足条件,则会导致Panic 错误,则撤销状态更改 - 用于检查内部错误。require(bool condition)
如果条件不满足则撤销状态更改 - 用于检查由输入或者外部组件引起的错误。require(bool condition, string memory message
如果条件不满足则撤销状态更改 - 用于检查由输入或者外部组件引起的错误,可以同时提供一个错误消息。revert()
终止运行并撤销状态更改。revert(string memory reason)
终止运行并撤销状态更改,可以同时提供一个解释性的字符串。
五、数学和密码学函数
addmod(uint x, uint y, uint k) returns (uint)
计算 (x+y)%k
,加法会在任意精度下执行,并且加法的结果即使超过 2**256
也不会被截取。从 0.5.0 版本的编译器开始会加入对 k!=0
的校验(assert)。
mulmod(uint x, uint y, uint k) returns (uint)
计算(x*y)%k
,乘法会在任意精度下执行,并且乘法的结果即使超过 2**256
也不会被截取。从 0.5.0 版本的编译器开始会加入对 k!=0
的校验(assert)。
keccak256((bytes memory) returns (bytes32)
计算 Keccak-256 哈希,之前keccak256
的别名函数sha3,
在0.5.0中已经移除。
sha256(bytes memory) returns (bytes32)
计算参数的 SHA-256 哈希。
ripemd160(bytes memory) returns (bytes20)
计算参数的 RIPEMD-160 哈希。
ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)
利用椭圆曲线签名恢复与公钥相关的地址,错误返回零值。
函数参数对应于 ECDSA签名的值:
r
= 签名的前 32 字节s
= 签名的第2个32 字节v
= 签名的最后一个字节
ecrecover
返回一个address
, 而不是address payable。
使用
ecrecover
,需要了解,在不需要知道相应的私钥下,签名也可以转换为另一个有效签名(可能是另外一个数据的签名)。在 Homestead 硬分叉,这个问题对于 _transaction_ 签名已经解决了(查阅 EIP-2)。 不过ecrecover
没有更改。除非需要签名是唯一的,否则这通常不是问题,或者是用它们来识别物品。 OpenZeppelin有一个 ECDSA助手库 ,可以将其用作
ecrecover
的”包装“,而不会出现此问题。
六、地址成员
<address>.balance
(uint256
) 以 Wei 为单位的
<address>.code
(bytes memory
)
<address>.codehash
(bytes32
)
<address payable>.transfer(uint256 amount) 发送数量为 amount 的 Wei
<address payable>.send(uint256 amount) returns (bool) 发送数量为 amount 的 Wei,失败时返回 false
<address>.call(bytes memory) returns (bool, bytes memory)
<address>.delegatecall(bytes memory) returns (bool, bytes memory)
<address>.staticcall(bytes memory) returns (bool, bytes memory)
三个调用成员,都可设置gas,但是只有call可以带value
在执行另一个合约函数时,应该尽可能避免使用
.call()
,因为它绕过了类型检查,函数存在检查和参数打包。
由于 EVM 会把对一个不存在的合约的调用作为是成功的。 Solidity 会在执行外部调用时使用 extcodesize 操作码进行额外检查。 这确保了即将被调用的合约要么实际存在(它包含代码)或者触发一个异常。
对地址而不是合约实例进行操作的低级调用
call()
,delegatecall()
,staticcall()
,send()
和transfer()
时,不会进行extcodesize检查,在GAS方面更便宜,但也更不安全。
在版本0.5.0之前,Solidity允许通过合约实例来访问地址的成员,例如
this.balance
,不过现在禁止这样做,必须显式转换为地址后访问,如:address(this).balance
。
在 0.5.0 版本以前,
call
,delegatecall
andstaticcall
仅仅返回成功状态,没有返回值。
七、合约相关
- this 指当前合约
- selfdestruct(address payable recipient)
selfdestruct
具有从EVM继承的一些特性:接收合约的 receive 函数 不会执行。 - 合约仅在交易结束时才真正被销毁,并且revert
可能会“撤消”销毁。
在 0.5.0 之前, 还有一个
suicide
,它和selfdestruct
语义是一样的。