Solidity 智能合约调试与扁平化:使用 Remix IDE 和 Truffle 本文介绍如何使用 Remix IDE 调试 Solidity 智能合约,以及使用 Truffle Flattener 扁平化合约代码以方便调试和验证。 关键要点: 合约扁平化: 将多个 Solidity 文件合并成一个文件,去除 import 语句,方便人工审查、Etherscan 验证和 Remix IDE 调试(Remix IDE 目前不支持 import)。 Remix IDE: 功能强大的 Solidity IDE,拥有优秀的逐步调试器,支持时间回溯、步骤切换、局部变量和状态探索、断点设置等功能。 Truffle 和 OpenZeppelin: 用于构建自定义 Token 的工具。Truffle Flattener 是一个 npm 工具,用于扁平化 Truffle 项目中的 Solidity 文件及其依赖项。 Remix IDE 调试方法: 根据用例的不同,有两种调试方法。可以通过引入错误来测试调试器功能,并使用 SafeMath 的 assert() 函数来强制规则并识别合约中的问题。 在以太坊主网上,智能合约使用真金白银,因此构建无错误的智能合约至关重要,需要使用调试器等专用工具。Remix IDE 是功能最全面的 Solidity IDE,它拥有一个出色的逐步调试器。您可以执行各种任务,例如:时间回溯、更改当前步骤、通过展开各种面板来探索局部变量和当前状态,以及设置断点以在代码的不同点之间移动。您还可以使用终端显示从 Remix 执行的交易并对其进行调试。 本教程将使用 Truffle 和 OpenZeppelin 构建一个简单的自定义 Token,解释为什么以及如何扁平化合约,最后使用 Remix IDE 开始调试合约。 为什么扁平化智能合约? 合约扁平化是指将所有 Solidity 代码合并到一个文件中,而不是多个源文件中,这样,就不需要 import 语句,导入的代码会嵌入到同一个文件中。我们需要扁平化智能合约的原因有很多,例如:手动审查合约、在 Etherscan 上验证合约或使用 Remix IDE 调试合约(因为它目前不支持 import)。 使用 Truffle 和 OpenZeppelin 编写简单的 Token Remix IDE 官方推荐用于构建小型合约或学习 Solidity,但是当您需要构建更大的合约或需要高级编译选项时,您必须使用 Solidity 编译器或其他工具/框架,例如 Truffle。 除了无错误的合约外,安全性也是构建智能合约的关键部分。出于这个原因,使用经过实战检验的框架(如 OpenZeppelin),它提供可重用、经过良好测试和社区审查的智能合约,这将有助于减少您的 DApp 中的漏洞。 让我们看看如何使用 Truffle 和 OpenZeppelin 创建一个简单的自定义 Token,它扩展了 OpenZeppelin 的标准 Token。 先决条件 本教程需要您具备 Truffle、以太坊和 Solidity 的一些知识。您可以阅读区块链入门和以太坊入门教程。 您还需要在系统上安装 Node.js 5.0 和 npm。请参考其下载页面了解说明。 安装 Truffle 使用您的终端,运行以下命令安装 Truffle: npm install -g truffle登录后复制登录后复制 创建新的 Truffle 项目 首先为您的项目创建一个新目录。让我们将其命名为 simpletoken 并导航到其中: mkdir simpletoken cd simpletoken truffle init登录后复制登录后复制 此命令将创建多个文件夹,例如 contracts/ 和 migrations/,以及部署合约到区块链时将使用的文件。 接下来,我们将安装 OpenZeppelin: npm install openzeppelin-solidity登录后复制登录后复制 创建简单的 Token 合约 在 contracts/ 文件夹内,创建一个名为 SimpleToken.sol 的文件并添加以下内容: pragma solidity ^0.4.23; import 'openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol'; contract SimpleToken is StandardToken { address public owner; string public name = 'SimpleToken'; string public symbol = 'STt'; uint8 public decimals = 2; uint public INITIAL_SUPPLY = 10000; constructor() public { totalSupply_ = INITIAL_SUPPLY; balances[owner] = INITIAL_SUPPLY; } }登录后复制 这是我们将要扁平化和调试的合约。我们正在导入 OpenZeppelin StandardToken.sol 合约并声明我们的 SimpleToken 合约,该合约使用 is 运算符扩展 StandardToken.sol。 我们的合约将继承许多变量和函数,需要覆盖这些变量和函数才能自定义合约。 为了完成我们的 Truffle 项目,在项目的 migrations/ 文件夹内,创建一个名为 2_deploy_contract.js 的文件并添加以下内容: var SimpleToken = artifacts.require("SimpleToken"); module.exports = function(deployer) { deployer.deploy(SimpleToken); };登录后复制 使用此文件,我们可以将智能合约部署/迁移到区块链中,但对于此示例,我们实际上不需要此文件,因为我们将使用 Remix IDE 在扁平化后部署智能合约。 使用 Truffle Flattener 扁平化合约 Truffle Flattener 是一个 npm 实用程序,它可以按照正确的顺序扁平化或组合在 Truffle 下开发的 Solidity 文件及其所有依赖项。 首先,使用以下命令从 npm 全局安装 truffle-flattener: npm install -g truffle-flattener登录后复制 接下来,在您的 Truffle 项目中,运行以下命令来扁平化 SimpleToken.sol 文件: truffle-flattener contracts/SimpleToken.sol > FlattenedSimpleToken.sol登录后复制 truffle-flattener 将扁平化的合约输出到标准输出或终端。使用 > 运算符,我们将输出保存到当前文件夹中的 FlattenedSimpleToken.sol 文件中。 使用 Remix IDE 编译和部署合约您可以从 FlattenedSimpleToken.sol 文件访问扁平化的智能合约。打开该文件并复制其内容。 接下来,从 //m.sbmmt.com/link/54af6860114f54728b5c2fd9b5cfeca9 打开 Remix IDE,并将扁平化的智能合约粘贴到 IDE 中的新文件中。 如果出现错误提示 Mock compiler : Source not found,请确保从 设置选项卡 > Solidity 版本面板 > 选择新的编译器版本下拉菜单 中选择较新的编译器版本。 如果 自动编译 已禁用,请单击 编译 面板中的 开始编译 按钮。 接下来,激活 运行 面板。首先确保您已为环境选择 JavaScript VM。在第二个框中,从下拉菜单中选择 SimpleToken 合约,然后单击下拉菜单下方的红色 部署 按钮。 您的合约已部署并在 JavaScript VM 上运行,该 VM 模拟区块链。我们现在可以开始以不同的方式对其进行调试。 调试自定义 Token 合约 为了了解如何调试合约,我们将首先引入一些错误。 您可以使用两种不同的方法在 Remix IDE 中开始调试智能合约,具体取决于用例。 当您第一次部署智能合约或随后执行任何交易时,一些信息将记录在终端中,您可以从日志旁边的白色 调试 按钮开始调试它。让我们看看它的实际操作。 使用 assert() SafeMath 是 OpenZeppelin 用于安全检查的数学运算库,这些检查会抛出错误。sub(a,b) 函数减去两个数字并返回一个无符号数字。第一个参数应该大于第二个参数,这样我们才能始终获得正数。该函数使用 assert() 函数强制执行此规则。这是 sub 函数的代码: npm install -g truffle登录后复制登录后复制 只要您为 a 和 b 提供验证条件 b < a 的值,执行就会继续进行,没有任何问题,但是一旦您提供 b 的值大于 a 的值,assert() 函数将抛出一个错误,提示: mkdir simpletoken cd simpletoken truffle init登录后复制登录后复制 因此,让我们在 SimpleToken 合约中添加对 sub() 的调用,其中参数错误: npm install openzeppelin-solidity登录后复制登录后复制 如果您重新部署合约,您将在终端中收到无效操作码错误: 单击 调试 按钮后,您将进入 调试器 面板,您可以在其中开始调试代码。 在代码编辑器中,第一行/指令将被突出显示,标记我们当前在代码中的位置。 单击 单步跳过 按钮以单步执行代码。 您也可以使用 跳转到异常 按钮直接跳转到异常。 无论您使用哪种方法,调试器都会将您带到导致问题的代码,然后停止。 您可以检查当前步骤中局部变量的状态。 Solidity 局部变量 面板显示与当前上下文关联的局部变量。 从源代码和 Solidity 局部变量 中,您可以得出结论,问题的根源与 assert() 方法和 b 的值大于 a 的值有关。 您可以使用 停止调试 按钮停止调试。 也值得查看调试器的其他面板。 指令 指令 面板显示被调试合约的字节码。当前步骤的字节码将被突出显示。 Solidity 状态 Solidity 状态 面板显示当前被调试合约的状态变量。 低级面板 这些面板显示有关执行的低级信息,例如步骤详细信息、内存、堆栈和函数的返回值。 结论 在本教程中,我们使用 Truffle 和 OpenZeppelin 构建了一个简单的 Token,然后使用 truffle-flattener 扁平化自定义合约,并使用 Remix IDE 开始调试合约中的错误。 希望这将帮助您大胆地深入逐步调试您自己的合约。请告诉我们您的使用情况! (后续内容,关于扁平化合约和在 Remix 中进行调试的常见问题解答,已省略,因为篇幅过长,且与核心内容关系较弱。如有需要,可以单独提出。)