Michael.W基于Foundry精读Openzeppelin第23期——ERC165Checker.sol

news2024/12/23 9:31:58

Michael.W基于Foundry精读Openzeppelin第23期——ERC165Checker.sol

      • 0. 版本
        • 0.1 ERC165Checker.sol
      • 1. 目标合约
      • 2. 代码精读
        • 2.1 supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId)
        • 2.2 supportsERC165(address account)
        • 2.3 supportsInterface(address account, bytes4 interfaceId)
        • 2.4 getSupportedInterfaces(address account, bytes4[] memory interfaceIds)
        • 2.5 supportsAllInterfaces(address account, bytes4[] memory interfaceIds)

0. 版本

[openzeppelin]:v4.8.3,[forge-std]:v1.5.6

0.1 ERC165Checker.sol

Github: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.3/contracts/utils/introspection/ERC165Checker.sol

ERC165Checker库是用来查询已实现IERC165的目标合约自身实现了哪些interface的工具库。在使用时需要注意:利用ERC165Checker提供的查询方法进行查询的过程不会因为目标合约没有实现待查询interface而发生revert。而是通过bool变量来标识目标合约对待查询interface的实现情况,查询方可以通过该bool值进行判断从而进行下一步的逻辑处理。

1. 目标合约

封装ERC165Checker library成为一个可调用合约:

Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/src/utils/introspection/MockERC165Checker.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol";

contract MockERC165Checker {
    using ERC165Checker for address;

    function supportsERC165(address account) external view returns (bool){
        return account.supportsERC165();
    }

    function supportsInterface(address account, bytes4 interfaceId) external view returns (bool){
        return account.supportsInterface(interfaceId);
    }

    function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)
    external
    view
    returns (bool[] memory){
        return account.getSupportedInterfaces(interfaceIds);
    }

    function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) external view returns (bool){
        return account.supportsAllInterfaces(interfaceIds);
    }

    function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) external view returns (bool){
        return account.supportsERC165InterfaceUnchecked(interfaceId);
    }
}

全部foundry测试合约:

Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/test/utils/introspection/ERC165Checker.t.sol

2. 代码精读

2.1 supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId)

查询目标地址account是否继承了interface id对应的interface。即只做对应interface id的显式支持interface检查,而不做对IERC165 interface的支持检查。

注:方法内部使用了内联汇编的staticcall,如果account合约没有实现IERC165 interface 也不会revert。

    function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
        // 拼接调用supportsInterface(bytes4 interfaceId)的calldata
        bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);

        // 内联汇编中static call目标合约的supportsInterface方法
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly {
        	// 内联汇编中的staticcall的参数为:staticcall(g, a, in, insize, out, outsize):
        	// - g: 本次调用时设置的gas上限为30000
        	// - a: call的合约地址为account
        	// - in: memory中的staticcall的calldata的起始位置,即encodedParams指针+32个字节
        	// - insize: memory中的staticcall的calldata的长度,即encodedParams指针指向内存中的值
        	// - out: memory中存放返回数据的起始位置,即memory中第一个字位置0x00
        	// - outsize: memory中存放返回数据的长度——0x20个字节(因为supportsInterface方法返回值为bool,内存中用一个字来存储)
        	// 注: 内联汇编staticcall详解参见博文:https://blog.csdn.net/michael_wgy_/article/details/132196437
            success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
            // static call的returndata的字节长度
            returnSize := returndatasize()
            // 从memory中取出staticcall的返回值,即bool返回值内容
            returnValue := mload(0x00)
        }
				
		// 返回true的条件(与关系):
		// 1. success为true —— static call成功调用;
		// 2. static call的return data字节长度>=32,即staticcall有返回数据;
		// 3. static call的返回值为true
        return success && returnSize >= 0x20 && returnValue > 0;
    }

foundry代码验证

import "openzeppelin-contracts/contracts/utils/introspection/ERC165.sol";
import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";

// all kinds of target contracts for test

// no method `supportsInterface(bytes4 interfaceId)`
contract SupportNone {}

contract SupportERC165 is ERC165 {}

contract SupportERC165ButNotInvalidInterfaceId is ERC165 {
    function supportsInterface(bytes4 interfaceId) public view override returns (bool) {
        return interfaceId == 0xffffffff || super.supportsInterface(interfaceId);
    }
}

interface ICustomized {
    function helloMichael() external view returns (string memory);
}

contract SupportManyInterfacesButNotERC165 is ERC20, ICustomized {
    string _str = "michael.w";

    constructor()ERC20("", ""){}

    function helloMichael() external view returns (string memory){
        return _str;
    }

    function supportsInterface(bytes4 interfaceId) public pure returns (bool) {
        return interfaceId == type(IERC20).interfaceId ||
        interfaceId == type(IERC20Metadata).interfaceId ||
        interfaceId == type(ICustomized).interfaceId;
    }
}

contract SupportManyInterfacesWithERC165 is ERC165, ERC20, ICustomized {
    string _str = "michael.w";

    constructor()ERC20("", ""){}

    function helloMichael() external view returns (string memory){
        return _str;
    }

    function supportsInterface(bytes4 interfaceId) public view override returns (bool) {
        return interfaceId == type(IERC20).interfaceId ||
        interfaceId == type(IERC20Metadata).interfaceId ||
        interfaceId == type(ICustomized).interfaceId ||
        super.supportsInterface(interfaceId);
    }
}

contract ERC165CheckerTest is Test {
    MockERC165Checker testing = new MockERC165Checker();

    SupportNone supportNone = new SupportNone();
    SupportERC165 supportERC165 = new SupportERC165();
    SupportERC165ButNotInvalidInterfaceId supportERC165ButNotInvalidInterfaceId = new SupportERC165ButNotInvalidInterfaceId();
    SupportManyInterfacesButNotERC165 supportManyInterfacesButNotERC165 = new SupportManyInterfacesButNotERC165();
    SupportManyInterfacesWithERC165 supportManyInterfacesWithERC165 = new SupportManyInterfacesWithERC165();
    bytes4 constant INTERFACE_ID_INVALID = 0xffffffff;

    function test_SupportsERC165InterfaceUnchecked() external {
        // case 1: query to contract SupportNone without revert and return false
        assertFalse(testing.supportsERC165InterfaceUnchecked(address(supportNone), type(IERC165).interfaceId));
        assertFalse(testing.supportsERC165InterfaceUnchecked(address(supportNone), INTERFACE_ID_INVALID));

        // case 2: query to contract SupportERC165
        assertTrue(testing.supportsERC165InterfaceUnchecked(address(supportERC165), type(IERC165).interfaceId));
        assertFalse(testing.supportsERC165InterfaceUnchecked(address(supportERC165), INTERFACE_ID_INVALID));

        // case 3: query to contract SupportERC165ButNotInvalidInterfaceId
        assertTrue(testing.supportsERC165InterfaceUnchecked(address(supportERC165ButNotInvalidInterfaceId), type(IERC165).interfaceId));
        assertTrue(testing.supportsERC165InterfaceUnchecked(address(supportERC165ButNotInvalidInterfaceId), INTERFACE_ID_INVALID));

        // case 4: query to contract SupportManyInterfacesButNotERC165
        assertFalse(testing.supportsERC165InterfaceUnchecked(address(supportManyInterfacesButNotERC165), type(IERC165).interfaceId));
        assertFalse(testing.supportsERC165InterfaceUnchecked(address(supportManyInterfacesButNotERC165), INTERFACE_ID_INVALID));
        assertTrue(testing.supportsERC165InterfaceUnchecked(address(supportManyInterfacesButNotERC165), type(IERC20).interfaceId));
        assertTrue(testing.supportsERC165InterfaceUnchecked(address(supportManyInterfacesButNotERC165), type(IERC20Metadata).interfaceId));
        assertTrue(testing.supportsERC165InterfaceUnchecked(address(supportManyInterfacesButNotERC165), type(ICustomized).interfaceId));

        // case 5: query to contract SupportManyInterfacesWithERC165
        assertTrue(testing.supportsERC165InterfaceUnchecked(address(supportManyInterfacesWithERC165), type(IERC165).interfaceId));
        assertFalse(testing.supportsERC165InterfaceUnchecked(address(supportManyInterfacesWithERC165), INTERFACE_ID_INVALID));
        assertTrue(testing.supportsERC165InterfaceUnchecked(address(supportManyInterfacesWithERC165), type(IERC20).interfaceId));
        assertTrue(testing.supportsERC165InterfaceUnchecked(address(supportManyInterfacesWithERC165), type(IERC20Metadata).interfaceId));
        assertTrue(testing.supportsERC165InterfaceUnchecked(address(supportManyInterfacesWithERC165), type(ICustomized).interfaceId));
    }
}

2.2 supportsERC165(address account)

检查目标地址account是否实现了IERC165 interface。

注:任何实现了IERC165的合约都必须支持对IERC165 interface id的显式支持查询和对invalid interface id (即0xffffffff)的显式不支持查询。

    // 按照EIP-165规范,任何接口的interface id都不应该是0xffffffff
    bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;

    function supportsERC165(address account) internal view returns (bool) {
        // 分别用IERC165 interface id和invalid interface id作为参数去static call目标合约的supportsInterface()方法。当返回值依次为true和false表示目标合约account完全支持IERC165 interface
        return
            supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
            !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID);
    }

foundry代码验证

contract ERC165CheckerTest is Test {
    MockERC165Checker testing = new MockERC165Checker();

    SupportNone supportNone = new SupportNone();
    SupportERC165 supportERC165 = new SupportERC165();
    SupportERC165ButNotInvalidInterfaceId supportERC165ButNotInvalidInterfaceId = new SupportERC165ButNotInvalidInterfaceId();
    SupportManyInterfacesButNotERC165 supportManyInterfacesButNotERC165 = new SupportManyInterfacesButNotERC165();
    SupportManyInterfacesWithERC165 supportManyInterfacesWithERC165 = new SupportManyInterfacesWithERC165();
    bytes4 constant INTERFACE_ID_INVALID = 0xffffffff;

    function test_SupportsERC165() external {
        // case 1: query to contract SupportNone without revert and return false
        assertFalse(testing.supportsERC165(address(supportNone)));

        // case 2: query to contract SupportERC165
        assertTrue(testing.supportsERC165(address(supportERC165)));

        // case 3: query to contract SupportERC165ButNotInvalidInterfaceId
        assertFalse(testing.supportsERC165(address(supportERC165ButNotInvalidInterfaceId)));

        // case 4: query to contract SupportManyInterfacesButNotERC165
        assertFalse(testing.supportsERC165(address(supportManyInterfacesButNotERC165)));

        // case 5: query to contract SupportManyInterfacesWithERC165
        assertTrue(testing.supportsERC165(address(supportManyInterfacesWithERC165)));
    }
}

2.3 supportsInterface(address account, bytes4 interfaceId)

检查目标地址account是否实现了输入interface id对应的interface。

注:该函数会同时检查目标地址是否支持IERC165 interface。

    function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
        // 当目标地址同时支持IERC165 interface和对应interface id才被认为是已支持对应interface id对应的interface
        return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
    }

foundry代码验证

contract ERC165CheckerTest is Test {
    MockERC165Checker testing = new MockERC165Checker();

    SupportNone supportNone = new SupportNone();
    SupportERC165 supportERC165 = new SupportERC165();
    SupportERC165ButNotInvalidInterfaceId supportERC165ButNotInvalidInterfaceId = new SupportERC165ButNotInvalidInterfaceId();
    SupportManyInterfacesButNotERC165 supportManyInterfacesButNotERC165 = new SupportManyInterfacesButNotERC165();
    SupportManyInterfacesWithERC165 supportManyInterfacesWithERC165 = new SupportManyInterfacesWithERC165();
    bytes4 constant INTERFACE_ID_INVALID = 0xffffffff;

    function test_SupportsInterface() external {
        // case 1: query to contract SupportNone
        assertFalse(testing.supportsInterface(address(supportNone), INTERFACE_ID_INVALID));
        assertFalse(testing.supportsInterface(address(supportNone), type(IERC165).interfaceId));

        // case 2: query to contract SupportERC165
        assertFalse(testing.supportsInterface(address(supportERC165), INTERFACE_ID_INVALID));
        assertTrue(testing.supportsInterface(address(supportERC165), type(IERC165).interfaceId));

        // case 3: query to contract SupportERC165ButNotInvalidInterfaceId
        assertFalse(testing.supportsInterface(address(supportERC165ButNotInvalidInterfaceId), INTERFACE_ID_INVALID));
        assertFalse(testing.supportsInterface(address(supportERC165ButNotInvalidInterfaceId), type(IERC165).interfaceId));

        // case 4: query to contract SupportManyInterfacesButNotERC165
        assertFalse(testing.supportsInterface(address(supportManyInterfacesButNotERC165), INTERFACE_ID_INVALID));
        assertFalse(testing.supportsInterface(address(supportManyInterfacesButNotERC165), type(IERC165).interfaceId));
        assertFalse(testing.supportsInterface(address(supportManyInterfacesButNotERC165), type(IERC20).interfaceId));
        assertFalse(testing.supportsInterface(address(supportManyInterfacesButNotERC165), type(IERC20Metadata).interfaceId));
        assertFalse(testing.supportsInterface(address(supportManyInterfacesButNotERC165), type(ICustomized).interfaceId));

        // case 5: query to contract SupportManyInterfacesWithERC165
        assertFalse(testing.supportsInterface(address(supportManyInterfacesWithERC165), INTERFACE_ID_INVALID));
        assertTrue(testing.supportsInterface(address(supportManyInterfacesWithERC165), type(IERC165).interfaceId));
        assertTrue(testing.supportsInterface(address(supportManyInterfacesWithERC165), type(IERC20).interfaceId));
        assertTrue(testing.supportsInterface(address(supportManyInterfacesWithERC165), type(IERC20Metadata).interfaceId));
        assertTrue(testing.supportsInterface(address(supportManyInterfacesWithERC165), type(ICustomized).interfaceId));
    }
}

2.4 getSupportedInterfaces(address account, bytes4[] memory interfaceIds)

批量检查目标地址account是否实现了输入interface ids对应的interface数组。返回值为一个bool数组,分别对应对相同index的interface ids数组成员的支持与否。

    function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)
        internal
        view
        returns (bool[] memory)
    {
        // 在内存中创建与传入interface ids数组相同长度的bool数组
        bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
        if (supportsERC165(account)) {
        	// 如果目标地址account已经完全支持IERC165 interface,才会进一步去检查传入的interface ids数组的支持情况。否则,直接认作全不支持
            for (uint256 i = 0; i < interfaceIds.length; i++) {
            	// 遍历查询目标account对各个interfaceId的支持情况,并将检查结果依次存入bool数组
                interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
            }
        }
				
		// 返回bool数组
        return interfaceIdsSupported;
    }

foundry代码验证

contract ERC165CheckerTest is Test {
    MockERC165Checker testing = new MockERC165Checker();

    SupportNone supportNone = new SupportNone();
    SupportERC165 supportERC165 = new SupportERC165();
    SupportERC165ButNotInvalidInterfaceId supportERC165ButNotInvalidInterfaceId = new SupportERC165ButNotInvalidInterfaceId();
    SupportManyInterfacesButNotERC165 supportManyInterfacesButNotERC165 = new SupportManyInterfacesButNotERC165();
    SupportManyInterfacesWithERC165 supportManyInterfacesWithERC165 = new SupportManyInterfacesWithERC165();
    bytes4 constant INTERFACE_ID_INVALID = 0xffffffff;

    function test_GetSupportedInterfaces() external {
        bytes4[] memory interfaceIds = new bytes4[](4);
        interfaceIds[0] = type(IERC165).interfaceId;
        interfaceIds[1] = type(IERC20).interfaceId;
        interfaceIds[2] = type(IERC20Metadata).interfaceId;
        interfaceIds[3] = type(ICustomized).interfaceId;

        // case 1: query to contract SupportNone
        bool[] memory supported = testing.getSupportedInterfaces(address(supportNone), interfaceIds);
        assertEq(supported.length, 4);
        // all false because of not supporting ERC165 completely
        assertFalse(supported[0]);
        assertFalse(supported[1]);
        assertFalse(supported[2]);
        assertFalse(supported[3]);

        // case 2: query to contract SupportERC165
        supported = testing.getSupportedInterfaces(address(supportERC165), interfaceIds);
        assertEq(supported.length, 4);
        assertTrue(supported[0]);
        assertFalse(supported[1]);
        assertFalse(supported[2]);
        assertFalse(supported[3]);

        // case 3: query to contract SupportERC165ButNotInvalidInterfaceId
        supported = testing.getSupportedInterfaces(address(supportERC165ButNotInvalidInterfaceId), interfaceIds);
        assertEq(supported.length, 4);
        // all false because of not supporting ERC165 completely
        assertFalse(supported[0]);
        assertFalse(supported[1]);
        assertFalse(supported[2]);
        assertFalse(supported[3]);

        // case 4: query to contract SupportManyInterfacesButNotERC165
        supported = testing.getSupportedInterfaces(address(supportManyInterfacesButNotERC165), interfaceIds);
        assertEq(supported.length, 4);
        // all false because of not supporting ERC165 completely
        assertFalse(supported[0]);
        assertFalse(supported[1]);
        assertFalse(supported[2]);
        assertFalse(supported[3]);

        // case 5: query to contract SupportManyInterfacesWithERC165
        supported = testing.getSupportedInterfaces(address(supportManyInterfacesWithERC165), interfaceIds);
        assertEq(supported.length, 4);
        // all true
        assertTrue(supported[0]);
        assertTrue(supported[1]);
        assertTrue(supported[2]);
        assertTrue(supported[3]);
    }
}

2.5 supportsAllInterfaces(address account, bytes4[] memory interfaceIds)

检查目标地址account是否全部实现了输入interface ids对应的interface数组。如果全部实现返回true,否则返回false。

注:每次调用调用supportsInterface(address account, bytes4 interfaceId)检查目标地址account对某一interface id的支持情况都会进行一次对IERC165的支持检查。而本方法中无论数组interfaceIds的长度是多少都只会进行一次对IERC165的支持检查,非常节约gas。

    function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
        // 如果目标地址account已经完全支持IERC165 interface,才会进一步去检查传入的interface ids数组的支持情况。否则,直接返回false
        if (!supportsERC165(account)) {
            return false;
        }

        // 遍历查询目标地址account对各个interface id的支持情况。只要出现任意一个interface id不支持的情况就直接返回false
        for (uint256 i = 0; i < interfaceIds.length; i++) {
            if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
                return false;
            }
        }

        // 当目标地址account对传入的各个interface id都支持时,返回true
        return true;
    }

foundry代码验证

contract ERC165CheckerTest is Test {
    MockERC165Checker testing = new MockERC165Checker();

    SupportNone supportNone = new SupportNone();
    SupportERC165 supportERC165 = new SupportERC165();
    SupportERC165ButNotInvalidInterfaceId supportERC165ButNotInvalidInterfaceId = new SupportERC165ButNotInvalidInterfaceId();
    SupportManyInterfacesButNotERC165 supportManyInterfacesButNotERC165 = new SupportManyInterfacesButNotERC165();
    SupportManyInterfacesWithERC165 supportManyInterfacesWithERC165 = new SupportManyInterfacesWithERC165();
    bytes4 constant INTERFACE_ID_INVALID = 0xffffffff;

    function test_SupportsAllInterfaces() external {
        bytes4[] memory interfaceIds = new bytes4[](4);
        interfaceIds[0] = type(IERC165).interfaceId;
        interfaceIds[1] = type(IERC20).interfaceId;
        interfaceIds[2] = type(IERC20Metadata).interfaceId;
        interfaceIds[3] = type(ICustomized).interfaceId;

        // case 1: query to contract SupportNone
        assertFalse(testing.supportsAllInterfaces(address(supportNone), interfaceIds));

        // case 2: query to contract SupportERC165
        assertFalse(testing.supportsAllInterfaces(address(supportERC165), interfaceIds));

        // case 3: query to contract SupportERC165ButNotInvalidInterfaceId
        assertFalse(testing.supportsAllInterfaces(address(supportERC165ButNotInvalidInterfaceId), interfaceIds));

        // case 4: query to contract SupportManyInterfacesButNotERC165
        assertFalse(testing.supportsAllInterfaces(address(supportManyInterfacesButNotERC165), interfaceIds));

        // case 5: query to contract SupportManyInterfacesWithERC165
        assertTrue(testing.supportsAllInterfaces(address(supportManyInterfacesWithERC165), interfaceIds));
    }
}

ps:
本人热爱图灵,热爱中本聪,热爱V神。
以下是我个人的公众号,如果有技术问题可以关注我的公众号来跟我交流。
同时我也会在这个公众号上每周更新我的原创文章,喜欢的小伙伴或者老伙计可以支持一下!
如果需要转发,麻烦注明作者。十分感谢!
在这里插入图片描述
公众号名称:后现代泼痞浪漫主义奠基人

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/861063.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker一键部署项目,无需登录XShell

文章目录 一键部署项目Docker手动部署SpringBoot项目编写docker部署的脚本文件script.sh 脚本内容 特别注意&#xff01;编写dockerfiledockerfile 文件内容 上传后端服务的jar包到服务器中执行 script 脚本部署后端服务 自动部署SpringBoot项目引入jsch依赖编写jsch工具类执行…

C# byte[]与Bitmap互转

首先先观察一下本地bmp图像结构(参考&#xff1a; https://blog.csdn.net/qq_37872392/article/details/124710600)&#xff1a; 可以看到bmp图像结构除了纯图像像素点位信息&#xff0c;还有一块未用空间(OffSet)。 所以如果需要得到图像所有数据进行转换&#xff0c;则可以使…

MySQL_SQL性能分析

SQL执行频次 语法&#xff1a; SHOW GLOBAL STATUS LIKE COM_类型; COM_insert; 插入次数 com_delete; 删除次数 com_update; 更新次数 com_select; 查询次数 com_______; 注意&#xff1a;通过语法&#xff0c;可以查询到数据库的实际状态&#xff0c;就可以知道数据库是以增删…

macos搭建appium-iOS自动化测试环境

目录 准备工作 安装必需的软件 安装appium 安装XCode 下载WDA工程 配置WDA工程 搭建appiumwda自动化环境 第一步&#xff1a;启动通过xcodebuild命令启动wda服务 分享一下如何在mac电脑上搭建一个完整的appium自动化测试环境 准备工作 前期需要准备的设备和账号&…

【独立版】新零售社区团购电商系统生鲜水果商城兴盛优选十荟团源码

【独立版】新零售社区团购电商系统生鲜水果商城兴盛优选十荟团源码

DNSlog注入(利用DNSlog平台将SQL盲注变成回显注入)

前言什么是UNC什么是DNSlog注入DNSlog注入的条件防止DNSlog注入的几个措施 sqli-labs试验 前言 前几天面试的时候&#xff0c;面试官问我知不知道OOB&#xff08;带外数据&#xff09;。 当时我蒙了&#xff0c;确实没听说过这个东西&#xff0c;然后面试官告诉我原来dnslog注入…

机器人CPP编程基础-04输入Input

机器人CPP编程基础-03变量类型Variables Types ……AI…… C #include<iostream> // 引入iostream库&#xff0c;这个库包含了对输入/输出进行操作所需的函数和对象 using namespace std; // 使用命名空间std&#xff0c;这样我们就可以直接使用std中的名字&#xff0c…

设定嵌入式linux系统的用户名和密码

遇到一个问题&#xff0c;板子上电后&#xff0c;串口可以正常输入命令行&#xff0c;而且不需要密码&#xff0c;用户名就是root &#xff0c;因为没有设置密码&#xff0c;但是SSH登录时用户名输入root&#xff0c;密码直接敲回车键也就是不输入密码竟然是错误的&#xff0c;…

一文带你入门Nacos:从安装到实例分析

目录 一、安装和配置 1.1 下载安装包 1.2 解压 1.3 端口配置 1.4 启动 1.5 访问 二、服务注册到nacos 2.1 引入依赖 2.2 配置nacos地址 2.3 重启 三、服务分级存储模型 3.1 给user-service配置集群 3.2 同集群优先的负载均衡 1&#xff09;给order-service配…

勘探开发人工智能技术:机器学习(3)

0 提纲 4.1 logistic回归 4.2 支持向量机(SVM) 4.3 PCA 1 logistic回归 用超平面分割正负样本, 考虑所有样本导致的损失. 1.1 线性分类器 logistic 回归是使用超平面将空间分开, 一边是正样本, 另一边是负样本. 因此, 它是一个线性分类器. 如图所示, 若干样本由两个特征描…

竞赛项目 深度学习疲劳驾驶检测 opencv python

文章目录 0 前言1 课题背景2 实现目标3 当前市面上疲劳驾驶检测的方法4 相关数据集5 基于头部姿态的驾驶疲劳检测5.1 如何确定疲劳状态5.2 算法步骤5.3 打瞌睡判断 6 基于CNN与SVM的疲劳检测方法6.1 网络结构6.2 疲劳图像分类训练6.3 训练结果 7 最后 0 前言 &#x1f525; 优…

Python爬虫 爬取图片

在我们日常上网浏览网页的时候&#xff0c;经常会看到一些好看的图片&#xff0c;我们就希望把这些图片保存下载&#xff0c;或者用户用来做桌面壁纸&#xff0c;或者用来做设计的素材。 我们最常规的做法就是通过鼠标右键&#xff0c;选择另存为。但有些图片鼠标右键的时候并没…

竞赛项目 深度学习的视频多目标跟踪实现

文章目录 1 前言2 先上成果3 多目标跟踪的两种方法3.1 方法13.2 方法2 4 Tracking By Detecting的跟踪过程4.1 存在的问题4.2 基于轨迹预测的跟踪方式 5 训练代码6 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的视频多目标跟踪实现 …

LabVIEW对并行机器人结构进行建模仿真

LabVIEW对并行机器人结构进行建模仿真 为了对复杂机器人结构的数学模型进行建模、搜索、动画和验证&#xff0c;在工业机器人动态行为实验室中&#xff0c;设计并实现了具有五个自由度的单臂型机器人。在研究台上可以区分以下元素&#xff1a;带有直流电机和编码器的机器人;稳…

竞赛项目 深度学习花卉识别 - python 机器视觉 opencv

文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &a…

安卓应用面试

Cordova 说明&#xff1a;一个移动框架&#xff0c;将HTML&#xff0c;CSS&#xff0c;JS封装为原生APP(hybird) 优点&#xff1a;跨平台&#xff0c;利于移植&#xff0c;能利用HTML5的各种特性&#xff0c;快速开发&#xff0c;成本低 缺点&#xff1a;不能使用设备的所以…

后端人员如何快速上手vue

一、环境搭建 了解更多vue-cli 官网地址:https://cli.vuejs.org/zh/guide/browser-compatibility.html 前提 1.安装node(js代码的运行环境)、npm、cnpm/yarn&#xff1b; nodejs官网&#xff1a;https://nodejs.org/en cnpm安装&#xff1a;https://www.python100.com/htm…

SQL常见命令语句

1.连接数据库 mysql (-h IP) -u root -p 密码2.查看数据库 show databases3.使用数据库 use db_name4.查看表 show tables [from db_name]5.查看表结构 desc tb_name6.创建、删除、选择数据库 create database db_namedrop database db_nameuse db_name7.数据类型 参考链…

【C语言】指针的进阶2

指针进阶 函数指针数组指向函数指针数组的指针回调函数指针和数组经典题目的解析 函数指针数组 数组是一个存放相同类型数据的存储空间&#xff0c;那我们已经学习了指针数组&#xff0c; 比如&#xff1a; int* arr[10];//数组的每个元素是int*那要把函数的地址存到一个数组…

React实现点击切换组件

实现如上组件 组件代码&#xff1a; import { SwapOutlined } from "ant-design/icons" import React, { useState } from "react" import ./index.lessinterface ISwitchTypeProps {onChange?: (val) > booleanactiveKey?: stringleft: { key: str…