前言
這一節(jié)主要會(huì)介紹一些Solidity API富稻,也就是一些特殊的變量及函數(shù)蜀变。
特殊的變量和函數(shù)(Special Variables and Functions)
Solidity的API中內(nèi)置了一些特殊的變量及函數(shù)绪杏,他們存在于全局命名空間(namespace)里,主要用于提供區(qū)塊鏈(blockchain)相關(guān)的信息,或者是一些通用的函數(shù)。大概分為如下幾類(lèi):
1汹粤、有關(guān)區(qū)塊和交易的屬性
2箩做、有關(guān)錯(cuò)誤處理
3虫腋、有關(guān)數(shù)學(xué)及加密功能
4骄酗、地址相關(guān)
5、合約相關(guān)
區(qū)塊和交易屬性(Block And Transaction Properties)
block.blockhash(uint blockNumber) returns (bytes32):返回給定區(qū)塊號(hào)的哈希值悦冀,只支持最近256個(gè)區(qū)塊趋翻,且不包含當(dāng)前區(qū)塊。
block.coinbase (address):當(dāng)前區(qū)塊的礦工地址
block.difficulty (uint): 當(dāng)前區(qū)塊的難度值
block.gaslimit (uint): 當(dāng)前區(qū)塊的gaslimit
block.number (uint): 當(dāng)前區(qū)塊的塊號(hào)
block.timestamp (uint): 當(dāng)前塊的Unix時(shí)間戳(從1970/1/1 00:00:00 UTC開(kāi)始所經(jīng)過(guò)的秒數(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):當(dāng)前調(diào)用發(fā)起人的地址
msg.sig (bytes4):調(diào)用數(shù)據(jù)(calldata)的前四個(gè)字節(jié)(例如為:函數(shù)標(biāo)識(shí)符)
msg.value (uint):發(fā)送這個(gè)消息所附帶的以太幣的數(shù)量,單位是wei
now (uint):當(dāng)前塊的時(shí)間戳(block.timestamp的別名)
tx.gasprice (uint):交易的gas價(jià)格
tx.origin (address):交易發(fā)送者的地址(full call chain)
注意以下幾點(diǎn):
1历等、msg的所有成員值讨惩,包括 msg.sender 和 msg.value都可以因?yàn)槊恳淮?external 函數(shù)(或library庫(kù)函數(shù))的調(diào)用被改變。
2募闲、不應(yīng)該依據(jù) block.timestamp(時(shí)間戳), now 和 block.blockhash(區(qū)塊哈希)來(lái)產(chǎn)生一個(gè)隨機(jī)數(shù)步脓,除非你確實(shí)需要這樣做愿待。
block.timestamp(時(shí)間戳)和 block.blockhash(區(qū)塊哈希)在一定程度上會(huì)受礦工的影響浩螺。比如在賭博合約里,不誠(chéng)實(shí)的礦工可能會(huì)嘗試去選擇一個(gè)對(duì)自己有利的hash仍侥。
3要出、對(duì)于同一個(gè)鏈上連續(xù)的區(qū)塊來(lái)說(shuō),當(dāng)前區(qū)塊的時(shí)間戳(timestamp)必然是大于上一個(gè)區(qū)塊的時(shí)間戳农渊。
4患蹂、由于可擴(kuò)展性的原因,你只能查到最近的256個(gè)區(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ù)可以在不實(shí)際調(diào)用函數(shù)的情況下传于,為函數(shù)調(diào)用創(chuàng)建數(shù)據(jù)。此外醉顽,keccak256(abi.encodePacked(a, b))是計(jì)算keccak256(a, b)更明確的方式沼溜,keccak256(a, b)在以后的版本中會(huì)被廢棄。
關(guān)于編碼的信息游添,大家可以參考ABI
和tightly packed encoding的文檔
錯(cuò)誤處理(Error Handling)
assert(bool condition)
用于判斷內(nèi)部錯(cuò)誤系草,如果條件不滿(mǎn)足時(shí),會(huì)使事物無(wú)效(拋出異常)
require(bool condition)
用于判斷輸入或外部組件錯(cuò)誤唆涝,如果條件不滿(mǎn)足時(shí)找都,會(huì)回滾
require(bool condition, string message)
用于判斷輸入或外部組件錯(cuò)誤,如果條件不滿(mǎn)足時(shí)廊酣,會(huì)回滾能耻。同時(shí)會(huì)顯示錯(cuò)誤信息
revert():
終止執(zhí)行并恢復(fù)改變的狀態(tài)
revert(string reason)
終止執(zhí)行并恢復(fù)改變的狀態(tài),并且會(huì)提供一個(gè)解釋的信息
數(shù)學(xué)及加密函數(shù)(Mathematical and Cryptographic Functions)
addmod(uint x, uint y, uint k) returns (uint):
計(jì)算(x + y) % k,加法支持任意的精度且不會(huì)在2**256(2的256次方)處溢出嚎京,從0.5.0版本開(kāi)始插入 assert(k != 0)嗡贺。
mulmod(uint x, uint y, uint k) returns (uint):
計(jì)算 (x * y) % k, 乘法支持任意的精度且不會(huì)在2*256處溢出鞍帝, 從0.5.0版本開(kāi)始插入 assert(k != 0)
keccak256(…) returns (bytes32):
計(jì)算 (tightly packed) arguments的Ethereum-SHA-3 (Keccak-256) hash值
sha256(…) returns (bytes32):
使用SHA-256計(jì)算tightly packed) arguments
的hash值
sha3(…) returns (bytes32):
keccak256的別名
ripemd160(…) returns (bytes20):
使用RIPEMD-160計(jì)算(tightly packed) arguments
的HASH值
ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address):
通過(guò)橢圓曲線(xiàn)簽名來(lái)恢復(fù)與公鑰關(guān)的地址诫睬,或者在錯(cuò)誤時(shí)返回0(參考示例
)。
可用于簽名數(shù)據(jù)的校驗(yàn)帕涌,如果返回結(jié)果是簽名者的公匙地址摄凡,那么說(shuō)明數(shù)據(jù)是正確的。
ecrecover函數(shù)需要四個(gè)參數(shù)蚓曼,需要被簽名數(shù)據(jù)的哈希結(jié)果值亲澡,r,s纫版,v分別來(lái)自簽名結(jié)果串床绪。
r = signature[0:64]
s = signature[64:128]
v = signature[128:130]
其中v取出來(lái)的值或者是00或01。要使用時(shí)其弊,我們先要將其轉(zhuǎn)為整型癞己,再加上27,所以我們將得到27或28梭伐。在調(diào)用函數(shù)時(shí)v將填入27或28痹雅。
在上面,“tightly packed”意思是說(shuō)參數(shù)不會(huì)補(bǔ)位糊识,是直接連接在一起的绩社,下面幾個(gè)是相等的。
keccak256("ab", "c")
keccak256("abc")
keccak256(0x616263) // hex16進(jìn)制數(shù)
keccak256(6382179)
keccak256(97, 98, 99) //ascii碼赂苗,97代表a
如果需要填充愉耙,可以使用顯式類(lèi)型轉(zhuǎn)換:keccak256(“\x00\x12”) 與keccak256(uint16(0x12))相同。
注意拌滋,常量將使用存儲(chǔ)它們所需的最少字節(jié)數(shù)來(lái)打包朴沿,例如keccak256(0) == keccak256(uint8(0))和keccak256(0x12345678) == keccak256(uint32(0x12345678))
在私有鏈(private blockchain)上運(yùn)行sha256,ripemd160或ecrecover可能會(huì)出現(xiàn)Out-Of-Gas錯(cuò)誤。因?yàn)樗芥湆?shí)現(xiàn)了一種預(yù)編譯合約鸠真,合約要在收到第一個(gè)消息后才會(huì)真正存在(即使它們的合約代碼是硬編碼的)悯仙。向一個(gè)不存在的合約發(fā)送消息時(shí)非常昂貴的,并且會(huì)導(dǎo)致Out-Of-Gas的問(wèn)題吠卷。一種解決辦法是在你真正使用這些合約之前锡垄,給每個(gè)合約地址發(fā)送1 wei。在官方和測(cè)試鏈上沒(méi)有這個(gè)問(wèn)題祭隔。
地址相關(guān)(Address Related)
<address>.balance (uint256):
指定以太坊地址的余額货岭,單位是wei
<address>.transfer(uint256 amount):
發(fā)送給定數(shù)量的ether到某個(gè)地址路操,以wei為單位。失敗時(shí)拋出異常千贯,還會(huì)轉(zhuǎn)發(fā)2300 gas屯仗,這是不可調(diào)節(jié)的。
<address>.send(uint256 amount) returns (bool):
發(fā)送給定數(shù)量的ether到某個(gè)地址搔谴,以wei為單位, 失敗時(shí)返回false魁袜,還會(huì)轉(zhuǎn)發(fā)2300 gas,這是不可調(diào)節(jié)的敦第。
<address>.call(...) returns (bool):
發(fā)起底層的call調(diào)用峰弹,失敗時(shí)返回false,會(huì)花費(fèi)掉所有可用的gas芜果,可以調(diào)節(jié)
<address>.callcode(...) returns (bool):
發(fā)起底層的callcode調(diào)用鞠呈,失敗時(shí)返回false,會(huì)花費(fèi)掉所有可用的gas右钾,可以調(diào)節(jié)蚁吝。不鼓勵(lì)使用,未來(lái)可能會(huì)移除舀射。
<address>.delegatecall(...) returns (bool):
發(fā)起底層的delegatecall調(diào)用窘茁,失敗時(shí)返回false,會(huì)花費(fèi)掉所有可用的gas后控,可以調(diào)節(jié)
更多的信息庙曙,參考Address.
警告:
使用send()會(huì)有一些危險(xiǎn):如果調(diào)用棧的深度超過(guò)1024或接收方耗光了gas空镜,交易都會(huì)失敗浩淘。所以,為了確保Ether交易安全吴攒,必須檢查send的返回值张抄,如果交易失敗,會(huì)回退以太幣洼怔。使用transfer或許是更好的選擇署惯。
合約相關(guān)(Contract Related)
this (current contract’s type):
表示當(dāng)前合約,可以顯式的轉(zhuǎn)換為Address
selfdestruct(address recipient):
銷(xiāo)毀當(dāng)前合約镣隶,并把所有資金發(fā)送到指定的地址极谊。
suicide(address recipient):
selfdestruct的別名(廢棄)
此外,當(dāng)前合約里的所有函數(shù)均可支持調(diào)用安岂,包括當(dāng)前函數(shù)本身轻猖。