---
title: "什么是 Solidity console log？"
description: "使用 Hardhat、Foundry 等工具打印日志并调试智能合约"
---

# 什么是 Solidity console log？

调试是[学习编写 Solidity 智能合约](https://www.alchemy.com/overviews/learn-solidity)、修补漏洞和修复问题 bug 过程中一个重要且反复出现的步骤。智能合约中两种典型的开发错误是运行时错误和逻辑错误。

利用能够帮助开发者理解代码的工具可以提升开发体验，尤其是在修复程序错误时。与 JavaScript 开发类似，`console.log()` 函数用于向 Web 控制台返回输出信息，从而辅助调试过程。

`console.log()` 接受一个参数（如数组、对象或消息），并将该值打印到 Web 控制台供开发者检查。这种方法使开发者能够通过逐步查看代码输出来定位可能出现的问题。

在本文中，我们将展示调试 [Solidity](https://www.alchemy.com/overviews/solidity) 的主要方式，介绍 [Hardhat](https://www.alchemy.com/dapps/hardhat)、Foundry、Truffle 和 [Brownie](https://www.alchemy.com/dapps/brownie) 中的调试工具，并提供调试技巧。

## **什么是 Solidity console log？**

将信息记录到控制台是调试代码时常用的工具，而 `console.log()` **是 Hardhat 提供的合约库中的一个函数。** 将信息输出到控制台有助于开发者理解并排查程序中的问题。在 [Solidity](https://www.alchemy.com/dapps/solidity) 中，这被称为事件（event）。

Ethereum 提供了一种日志功能，将数据存储在区块链交易的日志数据结构中。Solidity 的事件为这一功能提供了一层抽象，使开发者能够将数据输出到区块链上。

由于日志与合约地址一同保留在区块链中，并可随区块访问，Solidity 开发者可以对区块链进行查询，引用特定的交易数据。

### **Solidity 事件的使用场景**

[Solidity 事件](https://www.alchemy.com/overviews/solidity-events)可以用于多种场景，包括测试智能合约、为交易数据建立索引、供前端开发引用等。最常见的是以下三种使用场景：

1. 在智能合约中返回可供前端使用的值
1. 作为异步触发机制，让智能合约发出事件以触发前端执行某个操作
1. 作为更经济的存储形式，因为数据存储在交易日志中

在事件中，参数可以指定为 indexed 或 non-indexed。如果合约已通过验证，日志中的交易数据将显示为已编码的形式，否则会显示为 non-indexed 或哈希形式。

在其他情况下，如果开发过程是在 **Hardhat** 这类支持性环境中进行，除了事件外还可以使用 `console.log()` 函数，其用法与 JavaScript 开发中的方式类似。

### **为什么 console log 很重要？**

**Console log 是开发者在智能合约调试过程中不可或缺的工具。** Console log 是程序测试环境（console）与用于输出数据的函数（log()）的组合。

本质上，console log 在测试环境中提供程序的输出，可用于开发和调试过程。如果程序中出现错误或问题，console log 通常是排查代码、定位 bug 根本原因的首要手段。

在编写 [Solidity 智能合约](https://www.alchemy.com/overviews/solidity-smart-contract)时，console log 同样是调试过程中提取代码信息、理解逻辑的有效手段。

### **Solidity 中的日志记录是如何工作的？**

**日志记录，又称事件监听协议或事件（event），是由交易和区块生成的信号，用于提供智能合约本身无法获取的信息。**

Solidity 有一个“事件”的概念。事件可以在智能合约函数中触发（emit），并可携带 0 到 4 个用于快速查找的 topic（已索引）。在 Solidity 中，使用 'emit' 关键字触发事件，该操作会被转换为 EVM 的操作码之一：LOG0、LOG1、……、LOG4。

由于合约数据存储在 State trie 中，而事件数据存储在 Transaction Receipts trie 中，智能合约本身无法读取事件数据。

交易数据或日志条目包括：

- **Address** - 合约的地址
- Topic - 事件中已索引的值
- Data - 事件中经 ABI 编码的值或未索引的值

## **Hardhat 中的 Solidity 调试工具**

[Hardhat](https://book.getfoundry.sh/) 是一个 Ethereum 开发环境，专注于帮助开发者在本地开发 Solidity 智能合约，并为其提供必要的 Solidity 调试工具。

Hardhat 提供一整套用于测试、编译、部署和调试[应用](https://www.alchemy.com/dapps/top/defi-dapps)的工具。借助 Hardhat Network，开发者可以通过 [Solidity 接口](https://www.alchemy.com/overviews/solidity-interface)在本地机器上创建、编译和部署智能合约。

### **1. Console.log**

在 Hardhat Network 中，`console.log()` 函数可以作为可靠的工具，用于输出日志信息并直接从 Solidity 代码中提取细节。Hardhat Network 的设计目标是无论交易是否失败，都能提供灵活、全面的执行检查。

#### **如何打印 Solidity console log**

Solidity console log 的打印方式与 JavaScript 类似。完成导入后，即可在函数内部使用 `console.log()` 函数，根据智能合约的上下文打印特定输出。以下代码说明了这一过程。

**首先，将 hardhat/console.sol 导入智能合约**

接下来，将 `console.log()` **函数添加到智能合约中的具体函数内：**

注意：只有在导入 hardhat/console.sol 之后，才能使用 Hardhat 的 console log 工具。

### **2. Solidity 堆栈跟踪（stack trace）**

Hardhat 的堆栈跟踪工具结合了 JavaScript 与 Solidity，在交易或调用失败时提供相应报告。这种自动化的错误报告为开发者评估和调试智能合约提供了有价值的信息。

### **3. 明确的错误类型**

Hardhat 提供多种明确的错误类型，可帮助开发者简化调试过程，包括：

- 通用（general）
- 网络（network）
- 任务定义（task definition）
- 参数（arguments）
- 依赖解析（dependencies resolution）
- 内置任务（built-in tasks）
- 构件（artifacts）
- 插件（plugins）
- 内部（internal）
- 源名称（source names）
- 合约名称（contract names）

### **Solidity console log 技巧：使用事件和函数改进调试**

事件可用于在调试和生产阶段将交易日志中的数据输出到控制台。事件可作为标记，用于指示某个流程是否已经发生，同时也能指示特定步骤是否出现问题。这一过程与 Solidity 中的[“require” 关键字](https://www.alchemy.com/overviews/solidity-require)类似，后者用于检查某个条件是否为真，只有在条件为真时才允许代码继续执行。

要开始使用事件和函数来改进调试，需要正确定义一个事件，并在函数中触发（emit）该事件。这两个步骤能确保该函数被调用时事件会随之发生。

## **其他 Solidity console log 工具**

虽然 Hardhat 是构建、测试和调试智能合约的行业标准 Solidity 开发工具，但也存在其他一些可用于排查 Solidity 代码问题的替代工具，包括 Foundry、Truffle 和 Brownie。

### **1. Foundry**

[Foundry](https://www.alchemy.com/dapps/foundry) 提供一整套 Ethereum 智能合约开发工具，支持依赖管理、智能合约编译、部署、测试以及链上交互。

Foundry 工具集可与 Hardhat 集成，在调试过程中使用其 `console.log()` 函数。开发者可以调用该函数并传入最多 4 个参数，参数类型包括 uint、string、bool 和 address。

#### **Forge**

Forge 是与 Foundry 集成的命令行（CLI）工具，用于测试、构建和部署智能合约。这一测试框架使开发者能够使用 Solidity 编写测试，同时结合 JavaScript 或 TypeScript，并解锁多项用于调试过程的功能。

forge `test` 命令可自动执行 Solidity 测试，并进一步提供结果摘要，包括日志和堆栈跟踪。forge `debug` 命令同样是一个交互式调试器，可将单个智能合约作为脚本进行检查，以定位程序中的错误。

#### **Cast**

Cast 是一个用于与 Ethereum RPC 调用交互的命令行界面（CLI）工具，可通过命令行完成智能合约调用、交易或链上数据检索等操作。

#### **Anvil**

Anvil 是与 Foundry 集成的本地测试网节点，支持通过前端或通过 RPC（远程过程调用）与兼容 EVM（[Ethereum Virtual Machine](https://www.alchemy.com/overviews/what-is-the-ethereum-virtual-machine-evm)）的网络交互，从而完成智能合约的部署和测试。

### **2. Truffle**

Truffle 为 Ethereum 智能合约开发者提供三类工具：开发环境、测试框架以及面向区块链的资产管道（asset pipeline）。Truffle 的完整生态系统为开发者提供了创建、测试和调试端到端去中心化应用所需的各种工具。

Truffle 提供的工具集包括：

- **智能合约工具集** - 编译、链接、部署等
- **调试** - 断点、变量分析、单步执行、自动化合约测试
- **管理** - 网络、包管理、迁移框架

**了解更多：** [https://trufflesuite.com/docs/truffle/](https://trufflesuite.com/docs/truffle/)

### **3. Brownie**

Brownie 是一个基于 Python 的 Ethereum 智能合约开发与测试框架，支持 [Solidity 和 Vyper](https://www.alchemy.com/overviews/solidity-vs-vyper)，分为四个类别：测试、调试、交互和部署。每个环节都能帮助开发者构建灵活的程序。

开发者可以使用多种调试工具，获取有关交易失败的详细信息，并定位、复现和排查 Solidity 错误。

- **TransactionReceipt.revert_ms** - 直接获取交易失败的说明信息
- **TransactionReceipt.error()** - 定位导致交易失败的智能合约根本原因及具体位置
- **TransactionReceipt.events** - 查看在被回滚（revert）的交易中触发的事件
- **TransactionReceipt.trace** - 查看包含交易信息的字典列表
- **TransactionReceipt.call_trace()** - 查看交易步骤的完整映射（trace）

开发者还可以使用 **pytest** 对智能合约进行单元测试，随后查看所提供的**堆栈跟踪（stack trace）**报告。

**了解更多：** [https://eth-brownie.readthedocs.io/en/v1.2.1/index.html ](https://eth-brownie.readthedocs.io/en/v1.2.1/index.html)

## **通过 Alchemy University 学习 Solidity console log**

本文介绍了开发 Solidity 智能合约时最常用的日志记录和调试工具。如果你正在学习 Solidity，为智能合约调试选择合适的工具，对解决开发过程中遇到的问题至关重要。

要开始或加速你的 Solidity 开发学习，可以参加 Alchemy University 提供的免费、为期 7 周的 [Solidity 开发者训练营](https://www.alchemy.com/university/courses/solidity?a=671a6a00bd)。该课程原本是由 ChainShot 授课、价值 3000 美元的认证课程，现已完全整合进 Alchemy！如果你完全没有开发经验，Alchemy 提供的**为期 3 周的 JavaScript 速成课程**是开始 Ethereum 训练营之前一个很好的先修课程。
