前言
這一節(jié)主要會介紹一些Solidity API,也就是一些特殊的變量及函數(shù)。
特殊的變量和函數(shù)(Special Variables and Functions)
Solidity的API中內(nèi)置了一些特殊的變量及函數(shù),他們存在于全局命名空間(namespace)里,主要用于提供區(qū)塊鏈(blockchain)相關的信息,或者是一些通用的函數(shù)。大概分為如下幾類:
1、有關區(qū)塊和交易的屬性
2、有關錯誤處理
3、有關數(shù)學及加密功能
4、地址相關
5、合約相關
區(qū)塊和交易屬性(Block And Transaction Properties)
block.blockhash(uint blockNumber) returns (bytes32):返回給定區(qū)塊號的哈希值,只支持最近256個區(qū)塊,且不包含當前區(qū)塊。
block.coinbase (address):當前區(qū)塊的礦工地址
block.difficulty (uint): 當前區(qū)塊的難度值
block.gaslimit (uint): 當前區(qū)塊的gaslimit
block.number (uint): 當前區(qū)塊的塊號
block.timestamp (uint): 當前塊的Unix時間戳(從1970/1/1 00:00:00 UTC開始所經(jīng)過的秒數(shù))
gasleft() returns (uint256):剩余的gas
msg.data (bytes):完整的調(diào)用數(shù)據(jù)calldata
msg.gas (uint):剩余的gas,在0.4.21版本中已經(jīng)棄用,并有gasleft()代替
msg.sender (address):當前調(diào)用發(fā)起人的地址
msg.sig (bytes4):調(diào)用數(shù)據(jù)(calldata)的前四個字節(jié)(例如為:函數(shù)標識符)
msg.value (uint):發(fā)送這個消息所附帶的以太幣的數(shù)量,單位是wei
now (uint):當前塊的時間戳(block.timestamp的別名)
tx.gasprice (uint):交易的gas價格
tx.origin (address):交易發(fā)送者的地址(full call chain)
注意以下幾點:
1、msg的所有成員值,包括 msg.sender 和 msg.value都可以因為每一次 external 函數(shù)(或library庫函數(shù))的調(diào)用被改變。
2、不應該依據(jù) block.timestamp(時間戳), now 和 block.blockhash(區(qū)塊哈希)來產(chǎn)生一個隨機數(shù),除非你確實需要這樣做。
block.timestamp(時間戳)和 block.blockhash(區(qū)塊哈希)在一定程度上會受礦工的影響。比如在賭博合約里,不誠實的礦工可能會嘗試去選擇一個對自己有利的hash。
3、對于同一個鏈上連續(xù)的區(qū)塊來說,當前區(qū)塊的時間戳(timestamp)必然是大于上一個區(qū)塊的時間戳。
4、由于可擴展性的原因,你只能查到最近的256個區(qū)塊的hash值,所有其它的將返回0.
ABI編碼函數(shù)(ABI Encoding Functions)
abi.encode(...) returns (bytes):
abi.encodePacked(...) returns (bytes):
abi.encodeWithSelector(bytes4 selector, ...) returns (bytes):
abi.encodeWithSignature(string signature, ...) returns (bytes):
注意:
這些編碼函數(shù)可以在不實際調(diào)用函數(shù)的情況下,為函數(shù)調(diào)用創(chuàng)建數(shù)據(jù)。此外,keccak256(abi.encodePacked(a, b))是計算keccak256(a, b)更明確的方式,keccak256(a, b)在以后的版本中會被廢棄。
關于編碼的信息,大家可以參考ABI
和tightly packed encoding的文檔
錯誤處理(Error Handling)
assert(bool condition)
用于判斷內(nèi)部錯誤,如果條件不滿足時,會使事物無效(拋出異常)
require(bool condition)
用于判斷輸入或外部組件錯誤,如果條件不滿足時,會回滾
require(bool condition, string message)
用于判斷輸入或外部組件錯誤,如果條件不滿足時,會回滾。同時會顯示錯誤信息
revert():
終止執(zhí)行并恢復改變的狀態(tài)
revert(string reason)
終止執(zhí)行并恢復改變的狀態(tài),并且會提供一個解釋的信息
數(shù)學及加密函數(shù)(Mathematical and Cryptographic Functions)
addmod(uint x, uint y, uint k) returns (uint):
計算(x + y) % k,加法支持任意的精度且不會在2**256(2的256次方)處溢出,從0.5.0版本開始插入 assert(k != 0)。
mulmod(uint x, uint y, uint k) returns (uint):
計算 (x * y) % k, 乘法支持任意的精度且不會在2*256處溢出, 從0.5.0版本開始插入 assert(k != 0)
keccak256(…) returns (bytes32):
計算 (tightly packed) arguments的Ethereum-SHA-3 (Keccak-256) hash值
sha256(…) returns (bytes32):
使用SHA-256計算tightly packed) arguments
的hash值
sha3(…) returns (bytes32):
keccak256的別名
ripemd160(…) returns (bytes20):
使用RIPEMD-160計算(tightly packed) arguments
的HASH值
ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address):
通過橢圓曲線簽名來恢復與公鑰關的地址,或者在錯誤時返回0(參考示例
)。
可用于簽名數(shù)據(jù)的校驗,如果返回結果是簽名者的公匙地址,那么說明數(shù)據(jù)是正確的。
ecrecover函數(shù)需要四個參數(shù),需要被簽名數(shù)據(jù)的哈希結果值,r,s,v分別來自簽名結果串。
r = signature[0:64]
s = signature[64:128]
v = signature[128:130]
其中v取出來的值或者是00或01。要使用時,我們先要將其轉(zhuǎn)為整型,再加上27,所以我們將得到27或28。在調(diào)用函數(shù)時v將填入27或28。
在上面,“tightly packed”意思是說參數(shù)不會補位,是直接連接在一起的,下面幾個是相等的。
keccak256("ab", "c")
keccak256("abc")
keccak256(0x616263) // hex16進制數(shù)
keccak256(6382179)
keccak256(97, 98, 99) //ascii碼,97代表a
如果需要填充,可以使用顯式類型轉(zhuǎn)換:keccak256(“\x00\x12”) 與keccak256(uint16(0x12))相同。
注意,常量將使用存儲它們所需的最少字節(jié)數(shù)來打包,例如keccak256(0) == keccak256(uint8(0))和keccak256(0x12345678) == keccak256(uint32(0x12345678))
在私有鏈(private blockchain)上運行sha256,ripemd160或ecrecover可能會出現(xiàn)Out-Of-Gas錯誤。因為私鏈實現(xiàn)了一種預編譯合約,合約要在收到第一個消息后才會真正存在(即使它們的合約代碼是硬編碼的)。向一個不存在的合約發(fā)送消息時非常昂貴的,并且會導致Out-Of-Gas的問題。一種解決辦法是在你真正使用這些合約之前,給每個合約地址發(fā)送1 wei。在官方和測試鏈上沒有這個問題。
地址相關(Address Related)
<address>.balance (uint256):
指定以太坊地址的余額,單位是wei
<address>.transfer(uint256 amount):
發(fā)送給定數(shù)量的ether到某個地址,以wei為單位。失敗時拋出異常,還會轉(zhuǎn)發(fā)2300 gas,這是不可調(diào)節(jié)的。
<address>.send(uint256 amount) returns (bool):
發(fā)送給定數(shù)量的ether到某個地址,以wei為單位, 失敗時返回false,還會轉(zhuǎn)發(fā)2300 gas,這是不可調(diào)節(jié)的。
<address>.call(...) returns (bool):
發(fā)起底層的call調(diào)用,失敗時返回false,會花費掉所有可用的gas,可以調(diào)節(jié)
<address>.callcode(...) returns (bool):
發(fā)起底層的callcode調(diào)用,失敗時返回false,會花費掉所有可用的gas,可以調(diào)節(jié)。不鼓勵使用,未來可能會移除。
<address>.delegatecall(...) returns (bool):
發(fā)起底層的delegatecall調(diào)用,失敗時返回false,會花費掉所有可用的gas,可以調(diào)節(jié)
更多的信息,參考Address.
警告:
使用send()會有一些危險:如果調(diào)用棧的深度超過1024或接收方耗光了gas,交易都會失敗。所以,為了確保Ether交易安全,必須檢查send的返回值,如果交易失敗,會回退以太幣。使用transfer或許是更好的選擇。
合約相關(Contract Related)
this (current contract’s type):
表示當前合約,可以顯式的轉(zhuǎn)換為Address
selfdestruct(address recipient):
銷毀當前合約,并把所有資金發(fā)送到指定的地址。
suicide(address recipient):
selfdestruct的別名(廢棄)
此外,當前合約里的所有函數(shù)均可支持調(diào)用,包括當前函數(shù)本身。