函式不能被聲明為視圖,因為這個表達式(可能)修改了狀態
編譯合約會返回此錯誤。
TypeError: Function cannot be declared as view because this expression (potentially) modifies the state. --> contracts/certification/token/CleanEnergyCertificateToken.sol:104:9: | 104 | contractAddress.call(abi.encodeWithSignature("getTokenProperties(uint256 tokenId)", tokenID)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
問題很明顯:
getTokenProperties()
在這種情況下,編譯器不知道函式的結構,因為我使用的是call。所以它不知道這getTokenProperties()
是一個不修改儲存的視圖函式。這是
getTokenProperties()
供參考的程式碼:function getTokenProperties(uint256 tokenId) public view returns (CleanEnergyCertificateTokenProperties memory) { require( tokenId >= 0 && tokenIdToProperties[tokenId].timestamp > 0, "Token and it's properties for with respective tokenId must exist!" ); return tokenIdToProperties[tokenId]; }
因此,這裡唯一的解決方案似乎是省略“視圖”修飾符。
問題:
getTokenProperties()
如果它具有真正的“視圖”函式的功能,它會消耗氣體,但它沒有被聲明為這樣。編輯:我剛剛發現我可以使用
staticcall
,而不是call
解決問題。但我的問題仍然存在。如果我忘記聲明函式和視圖怎麼辦?會耗油嗎?我猜不是,但我不確定。
對此有幾種不同的看法。讓我們來看看。
區塊鏈的觀點
區塊鏈基本上只是儲存數據。可以從任何節點讀取數據。狀態更改不是免費的,從節點讀取數據是免費的。區塊鏈不知道是否有人從節點本地讀取數據——它只關心是否有人發出交易以更改區塊鏈狀態,以及成本。
工裝
圍繞區塊鏈的工具提供了呼叫合約功能的不同方式。修改區塊鏈狀態總是需要一個真實的交易。但是對非視圖函式發出靜態呼叫也很好——在這種情況下,wannabe-transaction 只發佈到您的本地節點(或您使用的任何節點提供程序)並且它執行的狀態更改不會持久化——但它的操作免費的。
工具的一個問題是它通常依賴於關於如何呼叫不同功能的各種“提示”。例如,如果你想呼叫一個非視圖函式,工具通常會為你提供一個真正的交易。
大多數工具(例如 ethers.js)提供了以任何類型呼叫任何函式的方法 - 本地/靜態呼叫或真實事務。這可能不是最直接的方法,因為該工具試圖讓你的事情變得簡單(假設你總是想要一個非視圖函式的真實事務)。
錢包
這些通常是相當簡化的工具版本,但對使用者更友好。例如,將您的錢包配置為對非視圖函式發出只讀呼叫可能很困難,如果不是不可能的話。這當然只適用於不是由各種工具觸發的功能(例如由執行 ethers.js 的網站)。
結論
理論上,是否發出真正的事務或本地只讀呼叫完全取決於呼叫者。實際上,這取決於所使用的工具,它們是否支持並且只提供他們認為您想要的東西。