0

solidity | 选择器

 1 year ago
source link: https://benpaodewoniu.github.io/2023/02/20/solidity63/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

selector 当我们调用智能合约时,本质上是向目标合约发送了一段 calldata,在 remix 中发送一次交易后,可以在详细信息中看见 input 即为此次交易的calldata

发送的 calldata 中前 4 个字节是 selector(函数选择器)。

msg.data

msg.datasolidity 中的一个全局变量,值为完整的 calldata(调用函数时传入的数据)。

在下面的代码中,我们可以通过 Log 事件来输出调用 mint 函数的 calldata

// event 返回msg.data
event Log(bytes data);

function mint(address to) external{
emit Log(msg.data);
}

当参数为 0x2c44b726ADF1963cA47Af88B284C06f30380fC78 时,输出的 calldata

0x6a6278420000000000000000000000002c44b726adf1963ca47af88b284c06f30380fc78

这段很乱的字节码可以分成两部分:

4 个字节为函数选择器 selector

0x6a627842

后面32个字节为输入的参数:

0x0000000000000000000000002c44b726adf1963ca47af88b284c06f30380fc78

其实 calldata 就是告诉智能合约,我要调用哪个函数,以及参数是什么。

method id、selector和函数签名

method id定义为函数签名的 Keccak 哈希后的前 4 个字节,当selectormethod id相匹配时,即表示调用该函数,那么函数签名是什么?

函数签名,为”函数名(逗号分隔的参数类型)”。

举个例子,上面代码中 mint 的函数签名为 mint(address) 。在同一个智能合约中,不同的函数有不同的函数签名,因此我们可以通过函数签名来确定要调用哪个函数。

注意,在函数签名中,uintint 要写为 uint256int256

我们写一个函数,来验证 mint 函数的 method id是否为 0x6a627842。大家可以运行下面的函数,看看结果。

function mintSelector() external pure returns(bytes4 mSelector){
return bytes4(keccak256("mint(address)"));
}

结果正是 0x6a627842

使用selector

我们可以利用 selector 来调用目标函数。例如我想调用 mint 函数,我只需要利用 abi.encodeWithSelectormint 函数的 method id 作为 selector 和参数打包编码,传给call函数:

function callWithSignature() external returns(bool, bytes memory){
(bool success, bytes memory data) = address(this).call(abi.encodeWithSelector(0x6a627842, 0x2c44b726ADF1963cA47Af88B284C06f30380fC78));
return(success, data);
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK