# 《Solidity 教程》特殊變數和函數 **Published by:** [Samumu.eth](https://paragraph.com/@samumu/) **Published on:** 2022-03-01 **URL:** https://paragraph.com/@samumu/solidity-10 ## Content 在全域命名空間中已經存在了(預設了)一些特殊的變數和函數,他們主要用來提供關於區塊鏈的資訊或一些通用的工具函數。區塊和交易屬性block.chainid (uint): 當前鏈 idblock.coinbase ( address): 挖出當前區塊的礦工位址block.difficulty ( uint): 當前區塊難度block.gaslimit ( uint): 當前區塊 gas 限額block.number ( uint): 當前區塊號block.timestamp ( uint): 自 unix epoch 起始當前區塊以秒計的時間戳msg.data ( bytes): 完整的 calldatamsg.sender ( address): 訊息發送者(當前呼叫)msg.sig ( bytes4): calldata 的前 4 位元組(也就是函數識別子)msg.value ( uint): 隨消息發送的 wei 的數量tx.gasprice (uint): 交易的 gas 價格tx.origin (address payable): 交易發起者(完全的調用鏈)以上這些都經常會使用到,請牢記這些每個的含義,以 Azuki.sol 為例block.timestamp 會用來判斷目前的區塊時間使否已經某個特定時間,例如當區塊時間超過拍賣開啟時間後,拍賣的 mint 函數才能成功被使用者呼叫msg.value 會用來判斷使用者給的 eth 數量是否足夠,例如公售的鑄造最低價格為0.1 eth,假設鑄造者只給了 0.05 eth,他理應不能鑄造msg.sender 則代表該呼叫者,大多需要與鏈上交互的函數都會需要使用到這個值 💡 對於每一個**外部函數**調用,包括 `msg.sender`和 `msg.value`在內所有 `msg`成員的值都會變化,包括對庫函數的調用ABI 編碼及解碼函數abi.decode(bytes memory encodedData, (...)) returns (...): 對給定的數據進行ABI解碼,而數據的類型在括弧中第二個參數給出 。 例如:(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes)) abi.encode(...) returns (bytes): ABI - 對給定參數進行編碼abi.encodePacked(...) returns (bytes):對給定參數執行 緊打包編碼 ,注意,可以不明確打包編碼。abi.encodeWithSelector(bytes4 selector, ...) returns (bytes): ABI - 對給定第二個開始的參數進行編碼,並以給定的函數選擇器作為起始的 4 位元組數據一起返回abi.encodeWithSignature(string signature, ...) returns (bytes):等價於 abi.encodeWithSelector(bytes4(keccak256(signature), ...)更多詳情請參考 ABI 和 緊打包編碼 💡 `keccak256` 是常用的計算 kecccak256 hash 的方式,是目前最常用的加密方式錯誤處理**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)**計算 Keccak256 哈希,Keccak256 在 solidity 的使用範例**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)**利用橢圓曲線簽名恢復與公鑰相關的地址,錯誤返回零值 💡 在一個私鏈上,你很有可能碰到由於 `sha256`、`ripemd160` 或者 `ecrecover`引起的 Out-of-Gas。 這個原因就是他們被當做所謂的預編譯合約而執行,並且在第一次收到消息后這些合約才真正存在(儘管合約代碼是硬代碼)。 發送到不存在的合約的消息非常昂貴,所以實際的執行會導致 Out-of-Gas 錯誤。 在你的合約中實際使用它們之前,給每個合約發送一點乙太幣,比如 1 Wei。 這在官方網路或測試網路上不是問題。地址成員**
.balance (uint256)**以 Wei 為單位的 位址類型 Address 的餘額。**.code (bytes memory)**在 位址類型 Address 上的代碼(可以為空).codehash (bytes32):Address 的 codehash**.transfer(uint256 amount)**向 位址類型 Address 發送數量為 amount 的 Wei,失敗時拋出異常,使用固定(不可調節)的 2300 gas 的礦工費**.send(uint256 amount) returns (bool)**向 位址類型 Address 發送數量為amount的 Wei,失敗時傳回 false,發送 2300 gas 的礦工費用,不可調節**.call(bytes memory) returns (bool, bytes memory)**用给定的有效payload發出低級CALL 調用,返回成功狀態及數據,發送所有可用 gas,也可以調節 gas。**.delegatecall(bytes memory) returns (bool, bytes memory)**用给定的有效payload發出低级 DELEGATECALL调用 ,返回成功狀態并返回數據,發送所有可用 gas,也可以調節 gas。 發出低级函數DELEGATECALL ,失敗时返回 false,發送所有可用 gas,可調節**.staticcall(bytes memory) returns (bool, bytes memory)**用给定的有效payload發出低級STATICCALL 調用,返回成功狀態及數據,發送所有可用 gas,也可以調節 gas合約相關**this ( 目前的合約型態 )**當前合約,可以顯示轉換為 位址類型 Address**selfdestruct(address payable recipient)**銷毀合約,並把餘額發送到指定 位址類型 Address ,請注意, selfdestruct具有從EVM繼承的一些特性:接收合約的 receive 函數 不會執行合約僅在交易結束時才真正被銷毀,並且 revert可能會「撤銷」銷毀此外,當前合約內的所有函數都可以被直接調用,包括當前函數。類型資訊表達式type(X) 可用於檢索參數X的類型資訊。 目前,此功能還比較有限( X僅能是合約和整型),但是未來應該會擴展 用於合約類型 C支援以下屬性:type(C).name : 獲得合約名type(C).creationCode : 獲得包含創建合同位元組碼的記憶體位元組陣組。 它可以在內聯彙編中構建自定義創建例程,尤其是使用 create2操作碼。 不能在合同本身或派生的合同訪問此屬性。 因為會引起迴圈引用。type(C).runtimeCode : 獲得合同的運行時位元組碼的記憶體位元組陣組。 這是通常由C的構造函數部署的代碼。 如果 C有一個使用內聯彙編的構造函數,那麼可能與實際部署的位元元組碼不同。 還要注意庫在部署時修改其運行時位元組碼以防範定期調用(guard against regular calls)。 與.creationCode 有相同的限制,不能在合同本身或派生的合同訪問此屬性。 因為會引起迴圈引用。除上面的屬性, 下面的屬性在介面類型 I 下可使用:**type(I).interfaceId:**返回介面I 的 bytes4類型的介面 ID,介面 ID 參考: EIP-165 定義對於整型 T有下面的屬性可訪問:type(T).min : T 的最小值type(T).max : T 的最大值 ## Publication Information - [Samumu.eth](https://paragraph.com/@samumu/): Publication homepage - [All Posts](https://paragraph.com/@samumu/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@samumu): Subscribe to updates - [Twitter](https://twitter.com/SamumuClan): Follow on Twitter