Solidity文檔(中文版)連載六:單位和全局變量

序言
本文是 Solidity 文檔(以太坊官方 Solidity 開發(fā)手冊)中文版連載的第六部分。這個連載的前五部分是智能合約概述安裝 Solidity 編譯器結合實例學習 Solidity源文件結構類型
這份文檔的英文原文可以在以太坊官網(wǎng)的最下方 Solidity 鏈接中找到。官方的英文版本文檔中有中譯版鏈接,即是本連載內(nèi)容的出處。這個連載將按照英文文檔的先后順序進行。
Solidity 是以太坊官方的智能合約開發(fā)高級語言。這份中文譯本是由 Hiblock 社區(qū)組織貢獻的,官方 Github:https://github.com/etherchina/solidity-doc-cn
我本人于 3 月初加入本項目,目前作為管理員、貢獻者和校訂人利用業(yè)余時間參與日常工作;截至到 5 月底,翻譯工作已接近完成。有興趣的朋友請直接在以太坊官網(wǎng)的鏈接中查看最新中文版本狀態(tài),或者關注上述中文譯本的 Github repository。
出于單獨閱讀的需要,我在連載中會刪除原文里的 rst 控制標簽、部分外部鏈接和文內(nèi)鏈接。
本文是對 Solidity 中的單位和全局變量的完整介紹。

單位和全局變量

以太幣單位

以太幣單位之間的換算就是在數(shù)字后邊加上 weifinneyszaboether 來實現(xiàn)的,如果后面沒有單位,缺省為 Wei。例如 2 ether == 2000 finney 的邏輯判斷值為 true

時間單位

秒是缺省時間單位,在時間單位之間,數(shù)字后面帶有 secondsminuteshoursdaysweeksyears 的可以進行換算,基本換算關系如下:

  • 1 == 1 seconds
  • 1 minutes == 60 seconds
  • 1 hours == 60 minutes
  • 1 days == 24 hours
  • 1 weeks == 7 days
  • 1 years == 365 days

由于閏秒造成的每年不都是 365 天、每天不都是 24 小時,所以如果你要使用這些單位計算日期和時間,請注意這個問題。因為閏秒是無法預測的,所以需要借助外部的預言機(oracle,是一種鏈外數(shù)據(jù)服務,譯者注)來對一個精確的日期庫進行更新。

注意:
基于上述原因 years 前綴已經(jīng)不推薦使用了。

這些后綴不能直接用在變量后邊。如果想用時間單位(例如 days)來將輸入變量換算為時間,你可以用如下方式來完成:

function f(uint start, uint daysAfter) public {
    if (now >= start + daysAfter * 1 days) {
        // ...
    }
}

特殊變量和函數(shù)

在全局命名空間中已經(jīng)存在了(預設了)一些特殊的變量和函數(shù),他們主要用來提供關于區(qū)塊鏈的信息。

區(qū)塊和交易屬性

  • block.blockhash(uint blockNumber) returns (bytes32): 給定區(qū)塊的哈希—僅對最近的 256 個區(qū)塊有效而不包括當前區(qū)塊
  • block.coinbase (address): 挖出當前區(qū)塊的礦工地址
  • block.difficulty (uint): 當前區(qū)塊難度
  • block.gaslimit (uint): 當前區(qū)塊 gas 限額
  • block.number (uint): 當前區(qū)塊號
  • block.timestamp (uint): 自 unix epoch 起始當前區(qū)塊以秒計的時間戳
  • gasleft() returns (uint256):剩余的 gas
  • msg.data (bytes): 完整的 calldata
  • msg.gas (uint): 剩余 gas
  • msg.sender (address): 消息發(fā)送者(當前調(diào)用)
  • msg.sig (bytes4): calldata 的前 4 字節(jié)(也就是函數(shù)標識符)
  • msg.value (uint): 隨消息發(fā)送的 wei 的數(shù)量
  • now (uint): 目前區(qū)塊時間戳(block.timestamp
  • tx.gasprice (uint): 交易的 gas 價格
  • tx.origin (address): 交易發(fā)起者(完全的調(diào)用鏈)

注意:
對于每一個外部函數(shù)調(diào)用,包括 msg.sendermsg.value 在內(nèi)所有 msg 成員的值都會變化。這里包括對庫函數(shù)的調(diào)用。

注意:
不要依賴 block.timestampnowblock.blockhash 產(chǎn)生隨機數(shù),除非你知道自己在做什么。

時間戳和區(qū)塊哈希在一定程度上都可能受到挖礦礦工影響。例如,挖礦社區(qū)中的惡意礦工可以用某個給定的哈希來運行賭場合約的 payout 函數(shù),而如果他們沒收到錢,還可以用一個不同的哈希重新嘗試。

當前區(qū)塊的時間戳必須嚴格大于最后一個區(qū)塊的時間戳,但這里唯一能確保的只是它會是在權威鏈上的兩個連續(xù)區(qū)塊的時間戳之間的數(shù)值。

注意:
基于可擴展因素,區(qū)塊哈希不是對所有區(qū)塊都有效。你僅僅可以訪問最近 256 個區(qū)塊的哈希,其余的哈希均為零。

ABI 編碼函數(shù)

  • abi.encode(...) returns (bytes):返回給定參數(shù)的 ABI 編碼
  • abi.encodePacked(...) returns (bytes):對給定參數(shù)進行打包的編碼
  • abi.encodeWithSelector(bytes4 selector, ...) returns (bytes):對從第二個參數(shù)開始的給定參數(shù)進行 ABI 編碼,并以第一個參數(shù)作為返回結果的前 4 字節(jié)——即用第一個參數(shù)作為函數(shù)選擇器(function selector),僅對其余參數(shù)進行 ABI 編碼
  • abi.encodeWithSignature(string signature, ...) returns (bytes):等價于 ``abi.encodeWithSelector(bytes4(keccak256(signature), ...)```

注意:
這些編碼函數(shù)可以用來基于函數(shù)調(diào)用的數(shù)據(jù)來產(chǎn)生 ABI 編碼,而不會實際調(diào)用一個函數(shù)。此外,keccak256(abi.encodePacked(a, b)) 是計算 keccak256(a, b) 的更明確的方式,后者在未來的版本中不再推薦使用。

關于 ABI 編碼的詳情請參考后續(xù)的“應用二進制編碼(ABI)說明”一章。

錯誤處理

  • assert(bool condition):如果條件不滿足則是交易不產(chǎn)生實際效果——用于內(nèi)部錯誤。
  • require(bool condition):如果條件不滿足則恢復(revert)——用于輸入或者外部組件引起的錯誤。
  • require(bool condition, string message):如果條件不滿足則恢復(revert)——用于輸入或者外部組件引起的錯誤,同時提供一個錯誤消息。
  • revert():終止運行并恢復(revert)狀態(tài)(state)變動。
  • revert(string reason):終止運行并恢復(revert)狀態(tài)(state)變動,并提供一個字符串信息來解釋原因。

數(shù)學和密碼學函數(shù)

  • addmod(uint x, uint y, uint k) returns (uint):計算 (x + y) % k,加法會在任意精度下執(zhí)行,并且加法的結果即使超過 2**256 也不會被截取。從 0.5.0 版本的編譯器開始會加入對 k != 0 的校驗(assert)。
  • mulmod(uint x, uint y, uint k) returns (uint):計算 (x * y) % k,乘法會在任意精度下執(zhí)行,并且乘法的結果即使超過 2**256 也不會被截取。從 0.5.0 版本的編譯器開始會加入對 k != 0 的校驗(assert)。
  • keccak256(...) returns (bytes32):計算“緊打包”參數(shù)(需要參考后續(xù)的“應用二進制編碼說明”一章)的 Ethereum-SHA-3 (Keccak-256)哈希。
  • sha256(...) returns (bytes32):計算“緊打包”參數(shù)(需要參考后續(xù)的“應用二進制編碼說明”一章)的 SHA-256 哈希。
  • sha3(...) returns (bytes32):等價于 keccak256。
  • ripemd160(...) returns (bytes20):計算“緊打包”參數(shù)(需要參考后續(xù)的“應用二進制編碼說明”一章)的 RIPEMD-160 哈希。
  • ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address):利用橢圓曲線簽名恢復與公鑰相關的地址,錯誤返回零值。參考示例

上文中的“緊打包(tightly packed)”是指不會對參數(shù)值進行 padding 處理(就是說所有參數(shù)值的字節(jié)碼是連續(xù)存放的,中間不保留為把長度補充為一個“字”,即 32 字節(jié),而追加的若干 0 值字節(jié)數(shù)據(jù),譯者注),這意味著下邊這些調(diào)用都是等價的:

keccak256("ab", "c")
keccak256("abc")
keccak256(0x616263)
keccak256(6382179)
keccak256(97, 98, 99)

如果需要 padding,可以使用顯式類型轉(zhuǎn)換:keccak256("\x00\x12")keccak256(uint16(0x12)) 是一樣的。

請注意,常量值會使用存儲它們所需要的最少字節(jié)數(shù)進行打包。例如:keccak256(0) == keccak256(uint8(0))keccak256(0x12345678) == keccak256(uint32(0x12345678))

在一個私鏈上,你很有可能碰到由于 sha256ripemd160 或者 ecrecover 引起的 gas 用盡(Out-of-Gas)問題。這個原因就是他們被當做所謂的預編譯合約而執(zhí)行,并且在第一次收到消息后這些合約才真正存在(盡管合約代碼是硬編碼)。發(fā)送到不存在的合約的消息非常昂貴,所以實際的執(zhí)行會導致 Out-of-Gas 錯誤。在你的合約中實際使用它們之前,給每個合約發(fā)送一點兒以太幣,比如 1 Wei。這在官方網(wǎng)絡或測試網(wǎng)絡上都不是問題。

地址相關

  • <address>.balance (uint256):以 Wei 為單位的某個地址(address)的余額。
  • <address>.transfer(uint256 amount):向某個地址(address)發(fā)送數(shù)量為 amount 的 Wei,失敗時拋出異常,且將額外發(fā)送 2300 gas 的礦工費,不可調(diào)整。
  • <address>.send(uint256 amount) returns (bool):向某個地址(address)發(fā)送數(shù)量為 amount 的 Wei,失敗時返回 false,且將額外發(fā)送 2300 gas 的礦工費用,不可調(diào)整。
  • <address>.call(...) returns (bool):執(zhí)行低級函數(shù) CALL,失敗時返回 false,會發(fā)送所有可用 gas,不可調(diào)整。
  • <address>.callcode(...) returns (bool):執(zhí)行低級函數(shù) CALLCODE,失敗時返回 false,會發(fā)送所有可用 gas,不可調(diào)整。
  • <address>.delegatecall(...) returns (bool):執(zhí)行低級函數(shù) DELEGATECALL,失敗時返回 false,會發(fā)送所有可用 gas,不可調(diào)整。

更多信息,請參考上一章中介紹的“地址”部分。

警告:
使用 send 有很多危險:如果調(diào)用棧深度已經(jīng)達到 1024(這總是可以由調(diào)用者所強制指定),轉(zhuǎn)賬會失敗;并且如果接收者用光了 gas,轉(zhuǎn)賬同樣會失敗。為了保證以太幣轉(zhuǎn)賬安全,總是檢查 send 的返回值,利用 transfer 或者后文中的更好的方式:
使用一種由接收者取回資金的模式。

注意:
如果通過一個低級函數(shù) delegatecall 來訪問一個存儲(storage)變量,兩個合約存儲中的數(shù)據(jù)布局(位置)必須一致,以保證可以在被調(diào)用的合約中通過變量名正確地訪問到調(diào)用合約中的存儲變量。這當然不是在高級的庫中通過函數(shù)參數(shù)傳遞存儲指針的那種情況。

注意:不鼓勵使用 callcode,并且將來它會被移除。

合約相關

  • this (current contract's type):當前合約,可以明確轉(zhuǎn)換為某個地址(address)。
  • selfdestruct(address recipient):銷毀合約,并把余額發(fā)送到指定的地址(address)。
  • suicide(address recipient):等價于 selfdestruct。

此外,當前合約內(nèi)的所有函數(shù)都可以被直接調(diào)用,包括當前函數(shù)。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,412評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,514評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,373評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,975評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,743評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,199評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,262評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,414評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,951評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,780評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,527評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,218評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,649評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,889評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,673評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內(nèi)容