19. Solidity:函數(shù)選擇器(函數(shù)簽名)

19.1 selector

當(dāng)我們調(diào)用智能合約時(shí),本質(zhì)上是向目標(biāo)合約發(fā)送了一段calldata,在remix中發(fā)送一次交易后,可以在詳細(xì)信息中看見(jiàn)input即為此次交易的calldata。

發(fā)送的calldata中前4個(gè)字節(jié)是selector(函數(shù)選擇器)。
示例代碼,將msg.data作為事件發(fā)出:

contract Selector {
    address public addr;
    event Log(bytes data);

    function selector(address _addr) external {
        addr = _addr;
        emit Log(msg.data);
    }
}

remix日志中的input:


input

Log信息(msg.data):

[
    {
        "from": "0xc5c97AAd92a962396229cbC8392e62585B04DfB3",
        "topic": "0xafabcf2dd47e06a477a89e49c03f8ebe8e0a7e94f775b25bbb24227c9d0110b2",
        "event": "Log",
        "args": {
            "0": "0x91fa5ace0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4",
            "data": "0x91fa5ace0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4"
        }
    }
]

可見(jiàn)input信息和全局變量msg.data相同,都是此次調(diào)用函數(shù)的calldata:

0x91fa5ace0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4

前四個(gè)字節(jié)為函數(shù)選擇器:
0x91fa5ace
后面32字節(jié)為傳入的參數(shù)(20字節(jié)的地址補(bǔ)零):
0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4

calldata作用是:告訴智能合約,要調(diào)用哪個(gè)函數(shù),以及參數(shù)是什么。

19.2 函數(shù)簽名、selector和method id

  • 函數(shù)簽名:"函數(shù)名(逗號(hào)分隔的參數(shù)類(lèi)型)",例如例子中selector()的函數(shù)簽名是:

    "selector(address)"

  • selector:函數(shù)選擇器為calldata的前四個(gè)字節(jié)。
  • method id:函數(shù)簽名哈希值的前四個(gè)字節(jié),例如:

    bytes4(keccak256("selector(address)"))

實(shí)現(xiàn)一個(gè)函數(shù)獲取上述例子中selector()函數(shù)的method id:

    function getSelector() external pure returns (bytes4){
        return bytes4(keccak256("selector(address)"));
    }

調(diào)用函數(shù)的返回值和函數(shù)選擇器相同,為0x91fa5ace。Solidity中通過(guò)函數(shù)選擇器(selector)匹配method id的方式確定要調(diào)用的函數(shù)。

19.3 selector的使用

我們可以利用selector來(lái)調(diào)用目標(biāo)函數(shù)。例如我想調(diào)用selector()函數(shù),我只需要利用abi.encodeWithSelector將selector()函數(shù)的method id作為selector和參數(shù)打包編碼,傳給call函數(shù):

    function useSelector(address _addr) external returns (bool) {
        (bool success, ) = address(this).call(abi.encodeWithSelector(0x91fa5ace, _addr));
        return success;
    }

調(diào)用selector()函數(shù)成功,輸出的Log:

[
    {
        "from": "0xf02A102153DDf132032B7De5D19F43aA049052Dd",
        "topic": "0xafabcf2dd47e06a477a89e49c03f8ebe8e0a7e94f775b25bbb24227c9d0110b2",
        "event": "Log",
        "args": {
            "0": "0x91fa5ace0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4",
            "data": "0x91fa5ace0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4"
        }
    }
]
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容