Solidity

你可以使用函式選擇器呼叫智能合約的內部函式嗎?

  • November 23, 2021

我有以下契約:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;
contract Selectors {
   
   bool public called;
   function callOtherFunc() public {
       bytes4 func = this.otherFunc.selector;
       (bool success, ) = address(this).call(abi.encodeWithSelector(func, true));
   }
   
   function otherFunc(bool _called) internal {
       called =_called; 
   }
}

但是,我遇到了錯誤:

TypeError: Member "otherFunc" not found or not visible after argument-dependent lookup in contract Selectors.

但如果我otherFunc公開,它編譯得很好。

此外,其他全域功能似乎不起作用

(bool success, ) = address(this).call(abi.encodeWithSignature("otherFunc(bool)", true));

或者

(bool success, ) = address(this).call(abi.encodeWithSelector(bytes4(keccak256(bytes("otherFunc(bool)"))), true));

這就是它的方式嗎?還有另一種使用選擇器呼叫內部函式的方法嗎?

無法通過函式選擇器直接呼叫內部函式。

合約的入口點基本上是一個帶有額外檢查的跳轉表,在 calldata 的前 4 個字節和合約的暴露函式之間尋找匹配的函式選擇器。

將您的函式標記為內部會將其從該跳轉表中排除,使其無法從外部呼叫中訪問。

採取以下契約:

contract SelectorsPublic {
   
   bool public called;
   
   function otherFunc(bool _called) public {
       called =_called; 
   }
}

我在這裡部署它。您可以在此處查看反編譯的字節碼。

在主函式體中明確檢查函式選擇器(提醒一下:keccak256("otherFunc(bool)")== 0x64feed76...):

else if (var0 == 0x64feed76) {
           // Dispatch table entry for 0x64feed76 (unknown)
           var1 = 0x0073;
           var2 = 0x006e;
           var4 = 0x04;
           var3 = var4 + (msg.data.length - var4);
           var2 = func_0109(var3, var4);
           func_006E(var2);
           stop();
       } 

反對,本契約(具有內部可見性):

contract SelectorsInternal {
   
   bool public called;
   
   function otherFunc(bool _called) internal {
       called =_called; 
   }
}

在此處部署和在此處反編譯沒有這樣的檢查。這意味著沒有通往otherFunc智能合約主要入口點的路徑。

只允許對其進行內部呼叫,外部呼叫將找不到匹配的條目並因此恢復(或者甚至不會像您的範例中那樣編譯)。

編輯:如果從反編譯的字節碼中您想知道檢查的內容0x50f9b6cd是什麼:這些與應用於自動生成的 getter 的原理相同:bool public calledkeccak256("called()")=0x50f9b6cd....

編輯2:

只有外部(或公共)函式具有以下成員:

.address: 返回函式合約的地址。

.selector: 返回 ABI 函式選擇器

因此,通過使用其中任何一個,您都在“外部”呼叫這些函式。

引用自:https://ethereum.stackexchange.com/questions/114137