全局变量与函数
在全局命名空间上,存在许多特殊的变量及函数,这些函数多用做提供与区块链相关的信息。
区块与交易相关
block
block
包含了各种与当前或早前区块相关的信息
名称 | 类型 / 函数签名 | 说明 |
---|---|---|
block.blockhash |
function (uint blockNumber) returns(bytes32) |
返回区块数为 blockNumber 的区块的哈希值。只能用于当前区块之前的 256 个区块,查询当前区块在内的其他区块都会返回 0。一定程度可以受到矿工的影响 |
block.coinbase |
address |
挖出当前区块的矿工的地址 |
block.difficulty |
uint |
当前区块的区块难度 |
block.gaslimit |
uint |
所有交易在内,当前区块允许消耗的 gas 的最大数目 |
block.number |
uint |
当前区块的区块数 |
block.timestamp now |
uint |
当前区块的时间戳,一定程度可以受到矿工的影响 |
提示:
除非清楚在做什么,不要依靠
block.timestamp
、now
或者block.blockhash
作为随机数的来源。时间戳和区块的哈希都能在一定程度上受到矿工的影响。如果将这些作为随机数的来源,会有被不怀好意的矿工利用,"随机"出对他们更有利的结果。
以太坊规定当前区块的时间戳必须严格大于上一个区块的时间戳。但这只能保证当前区块的时间戳在社区中较权威的链中,大小在相邻的两个区块的时间戳之间。
提示:
出于规模的考虑,调用
block.blockhash
只能获取当前区块之外的最近的 256 个区块的哈希值。查询其他任何区块(包括当前区块)的哈希值都只会得到 0。
msg
msg
包含了各种与当前合约调用者所发消息有关的信息
名称 | 类型 / 函数签名 | 说明 |
---|---|---|
msg.data |
bytes |
存放了完整的 calldata |
msg.gas |
uint |
gasleft 函数代替。 |
gasleft |
function() returns(uint256) |
返回剩余可以使用的 gas |
msg.sender |
address |
(当前调用中)消息发送者的地址 |
msg.sig |
bytes4 |
calldata 的首四字节(即,函数的标识符) |
msg.value |
uint |
消息中附带的 wei 的数量 |
提示:
msg
中的任何成员,包括msg.sender
、msg.value
随时都会因调用外部函数而改变,这也包括调用库中的函数。
tx
tx
包含了各种与当前交易相关的信息
名称 | 类型 / 函数签名 | 说明 |
---|---|---|
tx.gasprice |
uint |
当前交易中的 gas 的价格 |
tx.origin |
address |
当前交易发送者的地址(位于完整调用链的最顶层) |
错误处理
本书有专门的章节讲解 Solidity 的错误处理机制。在此,仅仅列出全局中用于处理错误的三个函数
函数 | 说明 |
---|---|
assert(bool condition) |
如果不符合 condition,抛出—用于处理内部错误。 调用 assert 不会归还调用者剩余的 gas |
require(bool condition) |
如果不符合 condition,抛出—用于处理在输入中或外部组件中的错误。调用 require 会归还调用者剩余的 gas |
revert() |
终止执行,撤销当前调用中的任何状态改变。调用 revert 会归还调用者剩余的 gas |
数学与密码学相关函数
函数 | 说明 |
---|---|
addmod(uint x, uint y, uint k) returns (uint) |
计算 (x + y) % k ,加法运算不会失去精度,也无需考虑溢出问题。Solidity 0.5.0 起,将会假设 k != 0 |
mulmod(uint x, uint y, uint k) returns (uint) |
计算 (x * y) % k ,乘法运算不会失去精度,$2^{256}$ 及以为的值无需考虑溢出。Solidity 0.5.0 起,将会假设 k != 0 |
keccak256(...) returns (bytes32) sha3(...) returns (bytes32) |
计算参数紧密打包后的 Ethereum-SHA-3 (Keccak-256) 哈希值 |
sha256(...) returns (bytes32) |
计算参数紧密打包后的 SHA-256 哈希值 |
ripemd160(...) returns (bytes20) |
计算参数紧密打包后的 RIPEMD-160 哈希值 |
ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address) |
用椭圆曲线签名恢复与公钥相关联的地址。若遇到错误,则返回 0 |
在一些私有区块链上,调用 sha256
、ripemd160
或 ecrecover
可能会遇到 Gas 不足 (Out-of-Gas) 的问题。出现此类问题是这些操作采用称为预编译合约的方式实现。这些合约只有在受到第一条消息后才会存在,而对不存在的合约发送消息有着更高昂的开销,因而出现 Gas 不足的错误。一种 workaround 是先向那些要用到的合约转一笔小钱(如 1 wei)。这类问题不会在以太坊官方及测试网络中出现。s
紧密打包 (tightly packed)
上表的"紧密打包"是指将各个参数紧密相连,没有填充。例如,以下语句都是相同的:
keccak256("Zz", "zz")
keccak256("Zzzz")
keccak256(0x5A7A7A7A)
keccak256(90, 122, 122)
如果需要填充,可以使用显式类型转换,例如:keccak256("\x00\x12")
等同于 keccak256(uint16(0x12))
。
此外,常量在打包时会使用最小可能的空间,因此,keccak256(0)
与keccak256(uint8(0))
相等,keccak256(0x12345678)
与 keccak256(uint32(0x12345678))
相等。