呼叫已部署合約的函式時,呼叫者合約轉發了多少gas?
考慮這個簡單的函式,
function setXFromAddress(address _addr, uint _x) public { Callee callee = Callee(_addr); callee.setX(_x); }
上面的程式碼從地址創建一個合約實例並呼叫它的方法。Solidity-by-example 表示與低級呼叫相比,這是推薦的方式。
我的問題是,有多少gas被轉發給被呼叫者合約?我知道通過電話我可以指定這樣發送多少,
function testCallFoo(address payable _addr) public payable { // You can send ether and specify a custom gas amount (bool success, bytes memory data) = _addr.call{value: msg.value, gas: 5000}( abi.encodeWithSignature("foo(string,uint256)", "call foo", 123) ); }
那麼是什麼決定了第一種情況下發送了多少呢?假設被呼叫函式是狀態改變函式。此外,是否有任何方法會創建新交易?
從 Solidity 0.5.0 開始,預設情況下,所有可用的 gas 都將通過外部呼叫進行轉發(請參閱changelog)。
但重要的是要注意“所有可用氣體”的含義。EIP-150定義了“除一個 64 之外的所有”規則,該規則規定始終至少有 1/64 仍未用於此交易的氣體不能被發送。
錢包如何確定交易需要多少 gas?
大多數錢包用於
eth_estimateGas
估計交易的總氣體使用量。Geth 通過設置氣體限制進行二進制搜尋來實現這一點,直到他們找到交易不會失敗的值(例如,從塊氣體限制開始,然後嘗試一半等)。如果您要求您的內部呼叫成功(例如
require(success, "Internal call failed")
),那麼此過程將估計正確的氣體量以使您的內部呼叫也成功(如果可能)。如果您不執行此操作,那麼估計的氣體可能低於所需的氣體,因為即使內部交易失敗,外部交易也會成功。在這種情況下,使用 other 可能是有意義的,以強制有足夠的 gas 可用(例如
require(gasleft() > 1000000, "I need a lot of gas")
,但不鼓勵硬編碼,因為 gas 成本會隨著時間而變化。最後一點:僅僅因為你指定了應該與呼叫一起發送的氣體,並不意味著真的會發送那麼多氣體。再次查看EIP-150,它定義瞭如果請求發送的氣體多於可用的氣體,那麼除了 1/64 之外的所有氣體都會被發送。