049.Solidity入门——36函数签名

函数签名是用来标识函数的唯一标识符,它由函数的名称参数类型组成。例如,函数 foo(uint256 a, string memory b) 的签名是 foo(uint256,string)。

Solidity 使用特定的哈希函数(例如 Keccak256)来计算函数签名的哈希值,然后取前四个字节作为函数选择器。函数选择器用于在调用合约时确定要执行哪个函数。

下面演示如何使用函数签名和选择器:

contract FunctionSignature {
    // 定义一个事件,用于记录调用的结果
    event Called(string name);

    // 定义一个公开的 foo 函数,接受两个参数
    function foo(uint256 a, string memory b) public {
        // 触发 Called 事件,传入 "foo" 作为参数
        emit Called("foo");
    }

    // 定义一个公开的 bar 函数,接受一个参数
    function bar(address c) public {
        // 触发 Called 事件,传入 "bar" 作为参数
        emit Called("bar");
    }

    // 定义一个外部的 fallback 函数,用于处理没有匹配到其他函数的调用
    fallback() external {
        // 获取 msg.data 的长度(字节数)
        uint256 length = msg.data.length;
        // 如果长度小于 4,则说明没有提供有效的函数选择器,直接返回
        if (length < 4) {
            return;
        }
        // 否则,从 msg.data 中取出前四个字节作为选择器,并存储到变量 selector 中
        bytes4 selector;
        assembly {
            selector := mload(add(msg.data, 0x20))
        }
        // 判断选择器是否等于 foo 函数的签名哈希值(前四个字节)
        if (selector == bytes4(keccak256("foo(uint256,string)"))) {
            // 如果是,则调用 foo 函数,并将 msg.data 中剩余的字节作为参数传入
            (bool success,) = address(this).delegatecall(
                abi.encodePacked(bytes4(keccak256("foo(uint256,string)")), msg.data[4:])
            );
            require(success);
            return;
        }
         // 判断选择器是否等于 bar 函数的签名哈希值(前四个字节)
         if (selector == bytes4(keccak256("bar(address)"))) {
             // 如果是,则调用 bar 函数,并将 msg.data 中剩余的字节作为参数传入
             (bool success,) = address(this).delegatecall(
                 abi.encodePacked(bytes4(keccak256("bar(address)")), msg.data[4:])
             );
             require(success);
             return;
         }
         // 如果都不匹配,则抛出异常
         revert();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_35369459/article/details/129338089