19.1 selector
當(dāng)我們調(diào)用智能合約時(shí)漆弄,本質(zhì)上是向目標(biāo)合約發(fā)送了一段calldata睦裳,在remix中發(fā)送一次交易后,可以在詳細(xì)信息中看見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:
Log信息(msg.data):
[
{
"from": "0xc5c97AAd92a962396229cbC8392e62585B04DfB3",
"topic": "0xafabcf2dd47e06a477a89e49c03f8ebe8e0a7e94f775b25bbb24227c9d0110b2",
"event": "Log",
"args": {
"0": "0x91fa5ace0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4",
"data": "0x91fa5ace0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4"
}
}
]
可見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ù)類型)"灾常,例如例子中
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中通過函數(shù)選擇器(selector)匹配method id的方式確定要調(diào)用的函數(shù)。
19.3 selector的使用
我們可以利用selector來調(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"
}
}
]