混音警告 - 未指定可見性,違反檢查 - 效果 - 互動模式,函式狀態可變性可以限制為純 - 可以忽略嗎?
兩個月前,我與 Remix.ethereum.org 編寫了一份智能合約。我的程式碼的第 1 行有:
pragma solidity ^0.4.11;
它編譯得很好,沒有錯誤也沒有警告。我在 Ropsten 中測試了每個功能,它執行良好。
現在,我越來越接近在主網上部署它了。我看到 Remix 已經改變了。現在,它說:
靜態分析提出了 50 條需要您注意的警告。
在分析選項卡下,有許多警告,我不知道如何解決。一個例子是,
TestContract.testFunction(address) 中的 Checks-Effects-Interaction 模式的潛在違規:可能導致重入漏洞。注意:此靜態分析目前不考慮修飾符。
另一個例子是,
功能瀏覽器/TestContract 的 Gas 需求 8.sol:MintableToken.transferFrom(address,address,uint256) 未知或不恒定。如果一個函式的gas需求高於block gas limit,它就不能被執行。請避免在修改大面積儲存的函式或操作中出現循環(這包括清除或複制儲存中的數組)
另一個例子是,
合約瀏覽器/TestContract 8.sol 的備份功能:測試需要太多gas(null)。如果回退功能需要超過 2300 個 gas,則合約無法接收 Ether。
另一個例子是,
Test.transferFrom(address,address,uint256):可能應該是常量,但不是。注意:此靜態分析目前不考慮修飾符。
上述每個範例都多次出現。我可以忽略所有這些警告嗎?如果沒有,我該如何解決它們?
在設置下,它使用的是 Solidity 版本 0.4.11。如果我將其更改為 0.4.17,我也會在 Compile 選項卡下收到許多警告。一個例子是,
browser/TestContract 8.sol:15:3 警告:未指定可見性。預設為“公共”:
功能寄存器(字元串鍵){
^
跨越多行。
我可以在每個函式中的參數的右括號後添加“public”來解決上述警告,但我不確定這是否是正確的做法。
另一個警告範例是,
browser/TestContract 8.sol:100:3 警告:函式狀態可變性可以限制為純
函式 mil(uint256 a, uint256 b) 內部常量返回 (uint256) {
^
跨越多行。
我不知道如何解決上述警告。
我是否正確地假設我可以忽略 0.4.17 並回到 0.4.11?
0.4.11 到 0.4.16 不會在 Compiler 選項卡下顯示這些警告。我應該使用 0.4.16 嗎?
我的程式碼可以在這裡看到
一般來說
您可以讓程式碼執行,忽略編譯器警告,但最好不要這樣做。大多數情況下,編譯器警告會警告您一些可能導致程式碼錯誤的事情。與編譯器錯誤相比,不同之處在於您的程式碼在語法上是正確的,因此可以編譯,但可能會導致問題,尤其是當有人嘗試做您不希望其他人做的事情時。
編譯器警告指示可能導致問題或可能具有程序員沒有意識到的意外影響的事情。
可以在此處找到有關此的好讀物,您也可以參考這個問題。最重要的是,閱讀 Solidity 文件中的安全注意事項。這可能會挽救你的生命!
無論如何,編譯器不像你那麼聰明,它聲稱它在語句中缺少
Note:
以下內容:注意:此靜態分析目前不考慮修飾符。
有時,這些註釋可能會告訴您可以安全地忽略這些警告的情況。
例子
您提到的一個錯誤警告是:
browser/TestContract 8.sol:15:3 警告:未指定可見性。預設為“公共”:
假設你有
function A(uint val) {}
. 由於您需要做一些先前的驗證,您希望它僅在契約中使用(這只是一個範例;))。如果在沒有驗證的情況下呼叫該函式,則可能會導致一些不需要的執行。唯一的用途function A
是在合約的其他一些函式中使用它。pragma solidity ^0.4.0; contract Example { function A(uint val) { //do something with val } function B(uint val){ //validation of val A(val); } }
現在,如果您像上面一樣保留契約,因為
function A()
預設情況下也設置為公開,任何使用您的契約的人都可以使用function A
任何uint
價值,這可能會造成麻煩。但是如果你有function A
聲明為的訪問修飾符private
,這個麻煩就不會出現,因為function A
不能公開訪問。由於您的要求也是function A
僅在契約中的其他功能內部使用,因此您的目標也實現了。當沒有聲明訪問修飾符時,編譯器假定一個函式是公共的,它會警告你它正在將函式設置為公共,並要求你檢查它是否真的應該是公共的。在上述情況下,您將收到有關函式和設置
function A
為私有和function B
公開的警告,因為現在編譯器知道您有意將其設為function B
公開和function A
私有。pragma solidity ^0.4.0; contract Example { function A(uint val) private { //do something with val } function B(uint val)public { //validation of val A(val); } }
關於
function B
設置為公開的警告是一種您可以放心忽略的警告,因為您的意圖也是相同的,但有關警告function A
是您真正應該考慮的事情。我的建議,
- 不要忽略警告,而是通過它們並檢查它們是否真的很重要,以及您期望程式碼的行為方式並嘗試解決它們。
- 嘗試使用最新的編譯器版本(atm 0.4.17),因為較新的穩定版本往往具有更少的錯誤和更多的功能(因此會產生新的警告)。
關於您收到的其他一些警告的一些見解
browser/TestContract 8.sol:100:3 警告:函式狀態可變性可以限制為純
您可以參考this answer和this question about the introduction of
view
andpure
type functions。TestContract.testFunction(address) 中的 Checks-Effects-Interaction 模式的潛在違規:
這是為了不遵循文件中描述的Checks-Effects-Interactions 模式。請參閱獲得此警告的函式並遵循文件中定義的模式以避免警告。
根據您發布的連結中的程式碼,我認為
closeSale()
警告可能是由於編譯器假設可能有重新進入的原因,因為您LogSaleClosed(uint256 issuedSupply, uint256 restrictedTokens)
在與令牌合約互動後呼叫成員事件。我可以建議的是在契約中包含該事件
token
。您可以在此處查看重入漏洞。它只是說如果那裡的錯誤程式碼讓另一個合約多次提取資金,因為它們在發送交易後更改了狀態變數份額,這可能需要一些時間讓另一個合約多次呼叫相同的函式,因為它保持msg.sender
值非零直到交易被執行。如果您在那裡看到好的程式碼,它們首先會首先設置shares[msg.sender]
為零。由於您是開發此功能的人,因此您知道預期事件的流程並且可以確定不會發生重入,因此忽略它是安全的。Test.transferFrom(address,address,uint256):可能應該是常量,但不是。注意:此靜態分析目前不考慮修飾符。
常量意味著它不會改變狀態。那是沒有狀態變數被改變。所以通常情況下,這些函式被稱為常量函式,並使用常量關鍵字定義。你可以讀到這個。
所以如果你的函式沒有改變任何狀態變數,你可以將它們聲明為常量。Solidity 正在提醒您這一點。