Definition and Detection of Defects in NFT Smart Contracts论文解读、复现

背景知识\定义

NFT

  • 是数字或物理资产所有权的区块链表示。
  • 不仅限于数字图片,视频和画作等艺术品也可以转化为 NFT 进行交易。
  • 近年来受到广泛关注,2021 年 NFT 交易额达到约 410 亿美元。

智能合约

  • 是在区块链上运行的图灵完备程序。
  • 支持各种去中心化应用 (DApp) 的部署。
  • 是 NFT 项目的底层技术。
  • 开发人员可以使用智能合约编码 NFT 交易规则。
  • 允许用户在交易市场上铸造和转移 NFT。

场景:

假设 Alice 想要购买一个 NFT,而 Bob 想要出售自己的 NFT。

  • 传统方式:
    Alice 和 Bob 需要找到一个中介机构,例如拍卖行或交易平台。
    他们需要签订一份合同,并支付手续费。
    中介机构负责验证交易并确保双方履行合同。
    交易完成后,中介机构将 NFT 转移给 Alice,并将资金转移给 Bob。

  • 智能合约方式:
    Alice 和 Bob 可以使用智能合约来执行交易。
    他们将 NFT 和资金存入智能合约。
    智能合约会自动验证交易条件,例如价格和数量。
    如果条件满足,智能合约会将 NFT 转移给 Alice,并将资金转移给 Bob。
    如果条件不满足,智能合约会自动退还 NFT 和资金。

EVM

EVM(以太坊虚拟机)是运行在以太坊区块链上的虚拟机,它负责执行智能合约代码

  • EVM 的执行机制:
    EVM 将智能合约的字节码拆分成操作码 (opcode)。
    EVM 遵循操作码的指令执行相应的操作,例如读取和写入状态变量、调用其他合约等。
    EVM 的执行过程是顺序执行的,但也可以通过跳转指令进行分支执行。

  • EVM 字节码的特点:
    跳转位置无法静态确定:EVM 的跳转指令 (例如 jump, jumpi) 的目标地址需要在运行时动态确定,这增加了智能合约代码的复杂性和安全性。
    没有返回指令:EVM 没有类似于函数调用的返回指令,而是通过状态转换完成函数调用和返回。

  • 智能合约中的数据存储:
    存储 (Storage): 用于存储永久数据,例如 NFT 的所有权信息、DeFi 合约的余额等。
    内存 (Memory): 用于存储临时数据,例如函数调用的参数和返回值、循环变量等。
    calldata: 用于存储函数调用的输入数据,例如交易数据、NFT 的 ID 等。

  • 智能合约中的状态变量:
    每个可变状态变量在编译时都会被分配一个 slot ID,指示其在存储空间中的位置。
    slot ID 帮助 EVM 在执行时确定状态变量的存储位置。
    对于复杂的数据类型,例如映射 (mapping) 和动态数组,需要结合 slot ID 和哈希计算来确定存储位置。

ERC-721

用于在智能合约中跟踪NFTs的一套规则和接口

  • ERC-721 标准:

    • 由以太坊改进提案(EIPs)定义,用于在智能合约中实现 NFT 的标准 API。
    • ERC-721 标准适用于非同质化、不可分割且独特的代币,这些代币代表特定数字或物理资产的所有权。
    • 与 ERC-20 标准不同,后者适用于可互换的同质化代币。
  • ERC-721 的关键功能:

    • approve:允许代币所有者授权另一个地址(_approved)管理特定的代币(_tokenId)。
    • setApprovalForAll:允许代币所有者授权一个操作者(_operator)管理他们所有的代币。
    • transferFrom:允许代币所有者、授权操作者或特定代币操作者转移代币所有权。
    • safeTransferFrom:与 transferFrom 类似,但增加了安全检查,确保接收方能够处理代币。
  • ERC-721 的接口:

    • ERC-721 标准定义了强制性和可选性的接口。
    • 开发者必须遵循 ERC-721 提出的开发注释来实现每个接口。
    • 每个 ERC-721 兼容的智能合约都应该实现 ERC-721 和 ERC-165 接口。
  • 安全性和元数据:

    • safeTransferFrom 函数会调用 onERC721Received 接口,确保接收方能够处理代币。
    • 钱包或代币接收者必须实现 onERC721Received 接口以支持代币转移。
    • ERC721Metadata 扩展允许代币所有者在铸造新代币时设置代币 URI,用户可以通过此接口查询代币代表的资产详情
    • ERC721Enumerable 接口允许 NFT 智能合约发布其完整的 NFT 列表,并使其可被发现。

存在的问题

the high value of NFTs also makes them a target for attackers. The defects in NFT smart contracts could be exploited by attackers to harm the security and reliability of the NFT ecosystem

NFT 的高价值也使其成为攻击者的目标。NFT 智能合约中的缺陷可能被攻击者利用,从而损害 NFT 生态系统的安全性和可靠性。

In addition, due to the immutability of smart contracts, it is critical to ensure that the NFT smart contract is bugfree before it is deployed on the blockchain.

智能合约的不可变性意味着一旦部署,就无法修改。因此,在将 NFT 智能合约部署到区块链之前,必须确保其没有缺陷。

Although a set of smart contract defects have been reported
in previous work [21], many scenarios cannot be covered due to
the increasing complexity and security requirements of smart contracts, e.g., NFT smart contracts

尽管之前的工作已经报告了一些智能合约缺陷,但无法涵盖 NFT 智能合约等复杂场景下的所有情况。

创新点

提出5种缺陷

  1. 数据收集:通过收集StackOverflow 帖子(使用“NFT”和“ERC721”标签进行过滤,我们获得了 672 个与 NFT 相关的 StackOverflow 帖子)和安全分析报告(例如 Medium、Twitter 以及知名区块链安全团队如 SlowMist 和 PeckShield 的官方网站,88份)
  2. 数据分析:在这里插入图片描述

1. Risky Mutable Proxy(风险可变代理):

  • 背景
    * OpenSea 是 NFT 生态系统中最大、最受欢迎的交易市场。
    * OpenSea 使用 Wyvern 协议来促进 NFT 的去中心化交易。
    * 当卖家首次在 OpenSea 上列出他们的 NFT 时,一个代理注册合约会创建一个智能合约,称为 OwnableDelegateProxy。
    * 这个合约存储了卖家的地址,代理注册合约可以使用这个新合约代表卖家采取行动并调用其他合约的方法。
    * 当卖家在他们 NFT 智能合约中列出任何项目时,他们会授权代理注册合约转移他们的代币。
    * 因此,用户不需要为每个 NFT 支付额外的 gas 费用以获取额外批准,使得交易变得简单。
  • 示例
    * 如果代理注册合约的地址可以被修改,那么所有用户的代币都可能被转移到攻击者手中。
    * 攻击者可以通过代理设置功能更改代理注册地址,而无需获得权限。

缺陷代码:

  1. setProxyRegistryAddress 函数

    function setProxyRegistryAddress(address proxyAddress)
    external onlyOwner {
        proxyRegistryAddress = proxyAddress;
    }
    
    • 这个函数允许合约的所有者设置一个新的代理合约地址。这是通过简单地将传入的proxyAddress赋值给状态变量proxyRegistryAddress来实现的。
    • 问题在于,如果合约的所有者是恶意的,或者所有者的私钥被泄露,那么攻击者可以利用这个函数将代理合约地址更改为一个他们控制的地址。
  2. isApprovedForAll 函数

    function isApprovedForAll(address owner, address operator) override public view returns (bool) {
        ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
        if (address(proxyRegistry.proxies(owner)) == operator) {
            return true;
        }
        return super.isApprovedForAll(owner, operator);
    }
    
    • 这个函数检查一个操作者是否有权代表所有者进行操作。它首先尝试通过代理合约来验证操作者是否被授权。
    • 如果proxyRegistry.proxies(owner)返回的地址与operator相匹配,那么函数返回true,表示操作者被授权。
    • 如果不匹配,它会调用父合约的isApprovedForAll函数来检查是否有其他形式的授权。

安全风险

  • 代理地址可修改性: 由于setProxyRegistryAddress函数允许修改代理合约地址,这可能被恶意行为者利用。如果代理合约地址被更改为攻击者控制的合约,那么攻击者可以通过这个代理合约来控制所有通过它授权的NFT。
  • 权限管理漏洞: isApprovedForAll函数的逻辑可能会导致未经授权的操作者获得对NFT的控制权,尤其是当代理合约的地址被恶意更改后。

2. ERC-721 Reentrancy(ERC-721可重入):

  • 定义: 在外部调用后修改状态变量。
  • 示例: 描述了一种情况,其中智能合约在调用外部合约(如在safeTransferFrom函数中)后,没有正确地锁定状态变量,导致可以重新进入(reentering)并修改状态,这可能会破坏合约的逻辑。

缺陷代码

function mintNFT(uint256 _numOfTokens, bytes memory _signature) public payable {
    // 预检查地址是否已经铸造过NFT
    (bool success, string memory reason) = canMint(msg.sender, _signature);
    require(success, reason);

    for (uint i = 0; i < _numOfTokens; i++) {
        _safeMint(msg.sender, totalSupply() + 1);
    }
    addressMinted[msg.sender] = true;
}
  1. 函数定义:

    • mintNFT 函数接受两个参数:_numOfTokens 表示要铸造的NFT数量,_signature 表示一些验证信息。
    • 该函数是 payable 的,意味着它可以接收以太币。
  2. 预检查:

    • canMint 函数被调用来检查 msg.sender(调用者地址)是否有权限铸造NFT。这个检查基于传入的签名。
    • 如果 canMint 返回 successfalse,则函数会停止执行并显示错误信息 reason
  3. 铸造NFT:

    • 通过一个循环,为每个要铸造的NFT调用 _safeMint 函数。
    • _safeMint 函数是安全铸造NFT的标准实践,它调用接收合约的 onERC721Received 钩子函数,以确保接收方合约能够接受NFT。
  4. 标记已铸造:

    • 循环结束后,将 addressMinted[msg.sender] 设置为 true,表示该地址已经铸造过NFT。

安全风险:

  • 可重入调用:_safeMint 调用期间,如果接收NFT的合约(可能是恶意的)实现了 onERC721Received 函数,它可以在 _safeMint 调用期间再次调用 mintNFT 函数。
  • 状态竞争条件: 因为 addressMinted[msg.sender] 在循环结束后才被设置为 true,如果在 _safeMint 调用期间 mintNFT 被重新调用,那么 canMint 的检查可能会被绕过,允许用户铸造超过限制的NFT。大多数情况下,这种重入调用会导致铸造的 NFT 数量超过稀有度阈值,损害其他买家的利益。

3. Unlimited Minting(无限铸造):

  • 定义: 在铸造NFT时不检查NFT的最大供应量。
  • 示例: 合约中没有适当的检查来限制铸造的NFT数量,可能导致超过预定数量的NFT被铸造,影响NFT的稀缺性和价值。

缺陷代码解析

function reserveApes() public onlyOwner {
    uint supply = totalSupply();
    uint i;
    for (i = 0; i < 30; i++) {
        _safeMint(msg.sender, supply + i);
    }
}
  1. 函数定义:

    • reserveApes 函数没有参数,并且只能由合约的所有者(onlyOwner)调用。
  2. 获取当前供应量:

    • 调用 totalSupply() 函数获取当前已铸造的NFT总量,并将其存储在变量 supply 中。
  3. 铸造NFT:

    • 通过一个循环,每次循环调用 _safeMint 函数来铸造一个新的NFT。
    • _safeMint 函数接受两个参数:接收者地址(在这里是 msg.sender,即合约所有者)和要铸造的NFT的ID(在这里是 supply + i)。

安全风险:

  • 无限制铸造: 这个函数没有检查每次铸造后是否超出了项目的预定最大供应量。由于在循环中连续调用 _safeMint,每次铸造的NFT ID都是基于当前供应量(supply),这可能导致铸造的NFT数量超出了项目的预定限制。
  • 潜在的经济影响: 如果攻击者或合约所有者滥用这个功能,他们可以无限制地铸造新的NFT,这将破坏NFT的稀缺性,从而对项目的货币价值和市场信任造成重大损害。

4. Missing Requirements(缺少要求):

  • 定义: 未遵循ERC-721标准接口的开发注释。
  • 示例: 开发者在实现合约时没有遵循ERC-721标准的要求,例如在approve函数中没有进行必要的权限检查,这可能导致安全问题。

缺陷代码解析

/* ERC-721 annotations on approve function */
// Throws unless msg.sender is the current NFT owner, or an authorized operator of the current owner.
function approve(address to, uint256 tokenId) public virtual override {
    address owner = ERC721.ownerOf(tokenId);
    require(to != owner, "ERC721: approval to current owner");
    /* missing requirement of checking msg.sender */
    _approve(to, tokenId);
}
  1. 函数注释:

    • 注释说明了 approve 函数的预期行为:除非 msg.sender 是当前NFT的所有者或被授权的操作者,否则应抛出异常。
  2. 获取NFT所有者:

    • owner 变量通过调用 ERC721.ownerOf(tokenId) 获取指定NFT的所有者地址。
  3. 检查接收者:

    • 使用 require 函数检查被授权的地址 (to) 是否不等于NFT的所有者 (owner)。如果是,将抛出异常,因为逻辑上不应该将NFT授权给其所有者。
  4. 缺少调用者检查:

    • 注释中提到缺少对 msg.sender 的检查,这是ERC-721标准中 approve 函数的一个重要要求。msg.sender 应该是NFT的所有者或被授权的操作者。
  5. 实际授权:

    • 调用 ERC721 合约的内部函数 _approve 来实际设置授权,允许地址 to 转移或操作指定的 tokenId

安全风险:

  • 授权给非所有者或非授权操作者: 由于缺少对 msg.sender 的检查,任何人都可以调用此 approve 函数尝试授权自己为特定NFT的操作者。如果这个缺陷被利用,攻击者可以授权自己操作他人的NFT,然后转移或以其他方式滥用这些NFT。

5. Public Burn(公开销毁):

  • 定义: 在销毁NFT的操作中未检查调用者权限。
  • 示例: 合约中的burn函数是公开的,没有适当的权限检查,任何用户都可以调用它来销毁他人的NFT,这显然违背了NFT所有权的基本原则。

缺陷代码解析

function burn(uint256 tokenId) public {
    _burn(tokenId);
}

function _burn(uint256 tokenId) internal virtual {
    address owner = ERC721.ownerOf(tokenId);
    // Clear approvals
    _approve(address(0), tokenId);
    _balances[owner] -= 1;
    delete _owners[tokenId];
}
  1. burn 函数:

    • burn 函数是公开的,意味着任何外部调用者都可以触发这个函数。
    • 它接受一个 tokenId 参数,代表要销毁的NFT的ID。
    • 函数内部直接调用了一个内部函数 _burn,传递了相同的 tokenId
  2. _burn 函数:

    • _burn 函数是内部的(internal),意味着它只能在合约内部或继承合约中被调用。
    • 它首先获取NFT的所有者地址。
    • 然后调用 _approve 函数,将NFT的授权地址设置为0,这表示撤销所有对该NFT的授权。
    • 接下来,减少所有者账户的余额计数。
    • 最后,使用 delete 语句从 _owners 映射中移除该NFT,实际上销毁了这个NFT。

安全风险:

  • 公开销毁权限: burn 函数是公开的,没有对调用者进行检查,这意味着任何外部调用者都可以销毁任何NFT,而不仅仅是他们自己的。这显然是一个严重的安全漏洞,因为它允许任何人销毁他人的资产。
  • 所有权检查缺失:_burn 函数中,尽管获取了NFT的所有者地址,但没有检查调用 burn 函数的地址是否与NFT的所有者地址相同。这导致了上述的安全风险。

设计NFTGuard 工具

NFTGuard工具概述

  1. 主要组件:

    • Inputter: 负责接收和处理输入的Solidity源代码。
    • Feature Detector: 用于检测合约中的关键特征,如映射存储、删除操作和外部调用。
    • CFG Builder: 基于符号执行构建控制流图(CFG),用于分析合约的执行路径。
    • Defect Identifier: 根据预定义的规则和模式识别和报告检测到的缺陷。
  2. 工作流程:

    • 用户输入Solidity源代码,该代码被编译成EVM字节码和抽象语法树(AST)以供进一步分析。
    • Inputter组件从AST中提取源映射信息,并使用槽映射来存储变量与它们槽ID之间的映射关系。
    • 通过Geth API将合约字节码反汇编成操作码(opcodes),然后动态构建CFG。
    • 在符号执行过程中,Feature Detector检测关键的操作特征,如映射存储、删除操作和外部调用。
    • Defect Identifier根据预定义的模式和规则报告检测到的缺陷。
  3. 结合源代码和字节码信息:

    • NFTGuard利用从源代码和字节码中提取的关键信息来提高检测的准确性和覆盖率。
    • 通过分析AST,NFTGuard能够获取状态变量的槽ID和数据类型,这些信息在符号执行期间用于监控特定变量的操作。
  4. 设计动机:

    • 使用源代码信息的目的是为了在执行特定操作码时定位缺陷代码,这有助于更有效地检测复杂的NFT智能合约。
  5. 扩展性:

    • NFTGuard被设计为一个可扩展的框架,支持最新的Solidity编译器版本(例如v0.8+),并允许开发者添加新的检测模式来识别更多类型的缺陷。

实验

数据集

Smart Contract Sanctuary 是一个专为在 Etherscan 上验证过的 Ethereum 智能合约提供存储的仓库。

作者通过关键词“NFT”或“ERC721”过滤,提取了 NFT 智能合约。

由于这篇论文撰写时最新的 Solidity 编译器版本是 0.8.16,作者选择了这个版本,并移除了无法编译的合约。
最终,作者获得了 16,527 个智能合约,并进行了大规模的实验。

评估效果

在这里插入图片描述

  1. 合约缺陷(Contract Defect):这列列出了NFTGuard检测到的缺陷类型。
  2. # Defects:这列显示了数据集中每个缺陷类型的数量。
  3. Per(%):这列显示了数据集中每个缺陷类型的百分比。
  4. # Samples:这列显示了为评估每个缺陷类型而随机抽取的样本数量。
  5. # TP:这列显示了每个缺陷类型中,被正确检测为缺陷的样本数量(真阳性)。
  6. # FP:这列显示了每个缺陷类型中,被错误检测为缺陷的样本数量(假阳性)。
  7. Prec(%):这列显示了每个缺陷类型的精确率,即真阳性与真阳性加假阳性总数之比。

在这里插入图片描述

关于随机抽取

作者通过以下步骤来评估 NFTGuard 的性能:

  1. 随机抽样:从每个缺陷的检测结果中随机抽取一定数量的合约。这些合约是 NFTGuard 报告为阳性的合约。
  2. 样本大小确定:为了确定每个缺陷的样本大小,作者采用了基于置信区间的抽样方法。这种方法旨在从总体中推断出特定缺陷的缺陷数量。
  3. 置信区间和置信水平:作者设定了 10% 的置信区间和 95% 的置信水平,并计算了需要收集的样本数量。
  4. 样本数量计算:根据计算结果,作者为五个缺陷分别计算了所需的样本数量,分别为 13、81、86、44 和 30。
  5. 数据集抽样和手动标注:根据计算结果,作者对数据集进行了抽样,并由两位作者仔细手动标注了这些样本。
  6. 真阳性和假阳性分离:在标注过程中,作者将样本分为真阳性和假阳性,以便分析 NFTGuard 的性能。
  7. 相关工作的采用:这种评估方法也被其他相关研究采用,以评估智能合约缺陷检测工具的性能。
    通过这种方法,作者能够评估 NFTGuard 在检测 NFT 智能合约缺陷方面的性能,包括其精确率和误报情况,从而回答 RQ2。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第 1 章:原生 AJAX

原生AJAX 1. AJAX 简介 AJAX 全称为 Asynchronous JavaScript And XML&#xff0c;就是异步的 JS 和 XML。通过 AJAX 可以在浏览器中向服务器发送异步请求&#xff0c;最大的优势&#xff1a;无刷新获取数据。AJAX 不是新的编程语言&#xff0c;而是一种将现有的标准组合在一…

C# Windows Forms实现绘制画板

目录 C# Windows Forms上绘制画板&#xff1a; 详细解释&#xff1a; TempData临时数据&#xff0c;用来保存画笔相关的信息&#xff0c;如&#xff1a;颜色&#xff0c;大小&#xff0c;坐标等 类声明和成员变量 构造函数 文件菜单项点击事件 保存菜单项点击事件 画笔大…

等待唤醒机制和阻塞队列

1. 等待唤醒机制 由于线程的随机调度&#xff0c;可能会出现“线程饿死”的问题&#xff1a;也就是一个线程加锁执行&#xff0c;然后解锁&#xff0c;其他线程抢不到&#xff0c;一直是这个线程在重复操作 void wait() 当前线程等待&#xff0c;直到被其他线程唤醒 void no…

网络安全(sql注入)

这里写目录标题 一. information_schema.tables 和 information_schema.schemata是information_schema数据库中的两张表1. information_schema.schemata2. information_schema.tables 二. 判断注入类型1. 判断数字型还是字符型注入2. 判断注入闭合是""还是 三. 判断表…

Keras深度学习中文文本分类

一.文本分类概述 文本分类旨在对文本集按照一定的分类体系或标准进行自动分类标记&#xff0c;属于一种基于分类体系的自动分类。文本分类最早可以追溯到上世纪50年代&#xff0c;那时主要通过专家定义规则来进行文本分类&#xff1b;80年代出现了利用知识工程建立的专家系统&…

电动机制造5G智能工厂工业物联数字孪生平台,推进制造业数字化转型

电动机制造5G智能工厂工业物联数字孪生平台&#xff0c;推进制造业数字化转型。5G智能工厂与物联数字孪生平台的融合应用&#xff0c;为电动机制造业的数字化转型铺设了一条高速通道。这一创新模式不仅极大地提升了生产效率&#xff0c;还深刻改变了产品的设计、生产、管理及运…

音视频入门基础:WAV专题(9)——FFmpeg源码中计算WAV音频文件每个packet的duration和duration_time的实现

音视频入门基础&#xff1a;WAV专题系列文章&#xff1a; 音视频入门基础&#xff1a;WAV专题&#xff08;1&#xff09;——使用FFmpeg命令生成WAV音频文件 音视频入门基础&#xff1a;WAV专题&#xff08;2&#xff09;——WAV格式简介 音视频入门基础&#xff1a;WAV专题…

深入理解Java虚拟机:Jvm总结-虚拟机字节码执行引擎

第八章 虚拟机字节码执行引擎 8.1 意义 不受物理条件制约地定制指令集与执行引擎的结构体系&#xff0c;能够执行那些不被硬件直接支持的指令集格式。输入的是字节码二进制流&#xff0c;处理过程是字节码解析执行的等效过程&#xff0c;输出的是执行结果 8.2 运行时栈帧结构…

一文读懂在线学习凸优化技术

一文读懂在线学习凸优化技术 在当今的数据驱动时代&#xff0c;机器学习算法已成为解决复杂问题的关键工具。在线学习凸优化作为机器学习中的一项核心技术&#xff0c;不仅在理论研究上具有重要意义&#xff0c;还在实际应用中展现出巨大的潜力。本文将深入浅出地介绍在线学习…

编程新纪元:AI如何成为你的编程伙伴

随着人工智能技术的不断进步&#xff0c;我们正步入一个编程的新纪元。在这个时代&#xff0c;AI不仅仅是一个工具&#xff0c;更是程序员的伙伴。它通过提供智能辅助、自动化编码和增强开发效率&#xff0c;正在改变我们编写和理解代码的方式。本文将探讨AI如何成为程序员的得…

精品PPT | 离散制造行业智能工厂总体解决方案

一、建设背景 离散制造业&#xff0c;包括机械制造业、汽车制造业和家电制造业等&#xff0c;其生产过程涉及多个不连续的工序&#xff0c;产品通常由多个零件装配而成。这类行业面临的挑战包括品种多、批量小、订单变化快、临时插单频繁以及外协件管理困难等问题&#xff0c;…

2025年第八届计算机图形和虚拟国际会议(ICCGV 2025)即将召开!

2025年第八届计算机图形和虚拟国际会议&#xff08;ICCGV 2025&#xff09;将于2025年2月21-23日在中国成都举行。随着信息技术的飞速发展&#xff0c;计算机图形学与虚拟现实技术正以前所未有的速度重塑着我们的认知世界与交互体验。从沉浸式游戏到精准医疗模拟&#xff0c;从…

如何将镜像推送到docker hub

前言 这一篇应该是最近最后一篇关于docker的博客了&#xff0c;咱来个有始有终&#xff0c;将最后一步——上传镜像给他写完&#xff0c;废话不多说&#xff0c;直接进入正题。 登录 首先需要确保登录才能推送到你的仓库中去&#xff0c;在终端输入docker login,输入用户名和…

AutosarMCAL开发——基于EB Gpt驱动

目录 1.Gpt原理2.EB配置以及接口应用2.1 EB配置2.2 接口应用 3.总结 1.Gpt原理 autosar GPT模块&#xff08;General Purpose Timer&#xff0c;通用定时器&#xff09;主要用于汽车ECU中的时间测量、计数和产生定时中断。它支持单次性和周期性定时器&#xff0c;可以在达到预…

阿里云机房火灾?盘点五大机房火灾现场

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 下午好&#xff0c;我的网工朋友。 不知道大家有没有看到今天有关阿里云的新闻&#xff0c;没错就是阿里云新加坡的网络节点出现了异常&#xff…

【828华为云征文|如何使用华为云Flexus X实例搭建私人博客:从配置到发布全指南】

文章目录 华为云Flexus X实例介绍搭建专属私人博客准备工作具体操作指南服务器环境确认宝塔软件商店操作一键部署WordPress私人博客域名解析WordPress安装初始页数据库信息配置运行安装程序配置博客信息博客管理后台&#xff08;默认为wp-login.php页面&#xff09;博客前台页面…

让AI成为打光工具人(Stable Diffusion进阶篇:Imposing Consistent Light)

前言 正巧我之前一直在学习的B站up也恢复了关于Stable Diffusion的教程&#xff0c;今天就一起来学习一下IC-Light&#xff0c;这样一项可以帮助喜欢拍照的同学们打光布景的插件。 IC-Light IC-Light的全称是Imposing Consistent Light&#xff0c;翻译过来就是给物体施加一…

Git 修改Push后的Commit Message

向远程仓库push代码之后&#xff0c;在IDEA中无法直接修改Commit Message&#xff0c;需要在终端或控制台中输入以下命令&#xff08;HEAD~1中的1表示只对最后一个提交进行修改&#xff0c;因此1可以自定义&#xff09; git rebase -i HEAD~1执行完rebase指令后&#xff0c;会…

F12抓包06-4:导出metersphere脚本

课程大纲 metersphere是一站式的开源持续测试平台&#xff0c;我们可以将浏览器请求导出为HAR文件&#xff0c;导入到metersphere&#xff0c;生成接口测试。 metersphere有2种导入入口&#xff08;方式&#xff09;&#xff0c;导入结果不同&#xff1a; 1.导入到“接口定义”…

白盒测试覆盖例题

答案&#xff1a;A D 知识点 定义 特点 语句覆盖 被测试程序中的每条语句至少测试一次 对执行逻辑覆盖很低&#xff0c;一般认为是很弱的逻辑覆盖 判定覆盖 被测试程序每个判定表达式至少落得一次“真”值和“假值” 判定覆盖比语句覆盖更强一些。判定可以是一个条件或…