跳转至主要内容

通过 SQL 学习以太坊基础主题

SQL
查询
交易
初学者
Paul Apivat
2021年5月11日
12 分钟阅读

面向开发者的以太坊教程很多,但缺少面向数据分析师或希望在不运行客户端或节点的情况下查看链上数据的人员的教育资源。

本教程通过 Dune Analyticsopens in a new tab 提供的界面,帮助读者使用结构化查询语言 (SQL) 查询链上数据,从而了解以太坊的基本概念,包括交易、区块和燃料。

链上数据可以帮助我们了解以太坊(它是一个网络,也是一个算力经济体),并且应该作为理解以太坊当今所面临挑战(即不断上涨的燃料价格)以及更重要的扩容解决方案相关讨论的基础。

交易

用户的以太坊之旅,始于初始化一个拥有 ETH 余额的用户控制帐户或实体。 帐户类型分为两种——用户控制帐户或智能合约(请参阅 ethereum.org)。

任何帐户都可以在 Etherscanopens in a new tabBlockscoutopens in a new tab 等区块浏览器上查看。 区块浏览器是访问以太坊数据的门户。 它们实时显示区块、交易、矿工、帐户及其他链上活动的数据(请参阅此处)。

然而,用户可能希望直接查询数据,以核对外部区块浏览器提供的信息。 Dune Analyticsopens in a new tab 为任何对 SQL 有一定了解的人提供了这种功能。

作为参考,以太坊基金会 (EF) 的智能合约帐户可以在 Blockscoutopens in a new tab 上查看。

值得注意的是,包括以太坊基金会的帐户在内的所有帐户都有一个公共地址,可用来发送和接收交易。

Etherscan 上的帐户余额由常规交易和内部交易构成。 尽管名为内部交易,但它们并不是改变链上状态的_真正_交易。 它们是通过执行合约发起的价值转移(来源opens in a new tab)。 由于内部交易没有签名,它们并未包含在区块链上,因此无法用 Dune Analytics 查询。

因此,本教程将侧重于常规交易。 可以这样查询:

1WITH temp_table AS (
2SELECT
3 hash,
4 block_number,
5 block_time,
6 "from",
7 "to",
8 value / 1e18 AS ether,
9 gas_used,
10 gas_price / 1e9 AS gas_price_gwei
11FROM ethereum."transactions"
12WHERE "to" = '\xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'
13ORDER BY block_time DESC
14)
15SELECT
16 hash,
17 block_number,
18 block_time,
19 "from",
20 "to",
21 ether,
22 (gas_used * gas_price_gwei) / 1e9 AS txn_fee
23FROM temp_table
显示全部

这将产生与 Etherscan 交易页面上提供的信息相同的信息。 为便于比较,以下是这两个来源:

Etherscan

Blockscout 上的 EF 合约页面。opens in a new tab

Dune Analytics

你可以在此处opens in a new tab找到看板。 点击表格查看查询(另请参阅上文)。

交易详解

一笔已提交的交易包含以下几项信息(来源):

  • 接收方:接收地址(查询时用 "to")
  • 签名:虽然由发送者的私钥签署交易,但我们可以用 SQL 查询的是发送者的公共地址("from")。
  • 价值:这是转移的 ETH 数量(请参阅 ether 列)。
  • 数据:这是经过哈希运算的任意数据(请参阅 data 列)
  • gasLimit – 交易可消耗的最大燃料单位数量。 燃料单位代表计算步骤
  • maxPriorityFeePerGas - 作为给矿工的小费所包含的最大燃料数量
  • maxFeePerGas - 愿意为交易支付的最大燃料数量(包括 baseFeePerGas 和 maxPriorityFeePerGas)

我们可以查询发送至以太坊基金会公共地址的交易中的这些具体信息:

1SELECT
2 "to",
3 "from",
4 value / 1e18 AS ether,
5 data,
6 gas_limit,
7 gas_price / 1e9 AS gas_price_gwei,
8 gas_used,
9 ROUND(((gas_used / gas_limit) * 100),2) AS gas_used_pct
10FROM ethereum."transactions"
11WHERE "to" = '\xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'
12ORDER BY block_time DESC
显示全部

区块

每笔交易都会改变以太坊虚拟机 (EVM) 的状态(来源)。 交易会广播到网络进行验证,并被包含在一个区块中。 每笔交易都与一个区块编号相关联。 要查看数据,我们可以查询一个具体的区块编号:12396854(在撰写本文时 [2021 年 5 月 11 日],这是以太坊基金会交易中最新的区块)。

此外,当我们查询下两个区块时,可以看到每个区块都包含上一个区块的哈希值(即父哈希),这说明了区块链是如何形成的。

每个区块都包含对其父区块的引用。 这在下面的 hashparent_hash 列之间有所显示(来源):

parent_hash

以下是 Dune Analytics 上的查询opens in a new tab

1SELECT
2 time,
3 number,
4 hash,
5 parent_hash,
6 nonce
7FROM ethereum."blocks"
8WHERE "number" = 12396854 OR "number" = 12396855 OR "number" = 12396856
9LIMIT 10
显示全部

我们可以通过查询时间、区块编号、难度、哈希值、父哈希值及随机数来检查一个区块。

此查询唯一未涵盖的是_交易列表_(这需要下文的单独查询)和_状态根_。 完整节点或归档节点将存储所有交易和状态转换,允许客户端随时查询链的状态。 因为这需要非常大的存储空间,我们可以将链数据与状态数据分开:

  • 链数据(区块列表、交易)
  • 状态数据(每次交易状态转换的结果)

状态根属于后者,是_隐式_数据(不存储在链上),而链数据是显式数据,存储在链本身上(来源opens in a new tab)。

在本教程中,我们将重点关注那些_可以_通过 Dune Analytics 用 SQL 查询的链上数据。

如上所述,每个区块都包含一个交易列表,我们可以通过筛选一个特定区块来查询它。 我们将尝试最新的区块 12396854:

1SELECT * FROM ethereum."transactions"
2WHERE block_number = 12396854
3ORDER BY block_time DESC`

下面是 Dune 上的 SQL 输出:

这个被添加到链上的区块,改变了以太坊虚拟机 (EVM) 的状态。 有时几十笔、甚至几百笔交易会同时得到验证。 在这个特定的案例中,包含了 222 笔交易。

要查看实际有多少笔成功交易,我们将添加另一个筛选器来计算成功的交易:

1WITH temp_table AS (
2 SELECT * FROM ethereum."transactions"
3 WHERE block_number = 12396854 AND success = true
4 ORDER BY block_time DESC
5)
6SELECT
7 COUNT(success) AS num_successful_txn
8FROM temp_table

对于区块 12396854,在 222 笔总交易中,有 204 笔成功验证:

交易请求每秒发生数十次,但区块大约每 15 秒提交一次(来源)。

要了解大约每 15 秒产生一个区块,我们可以用一天的总秒数 (86400) 除以 15,得到估算的每日平均区块数量(约 5760 个)。

每天产生的以太坊区块数量图表(2016 年至今)如下所示:

这段时间内每天生产的平均区块数量大约 5,874 个:

查询如下:

1# 用于可视化自 2016 年以来每日产出区块数量的查询
2
3SELECT
4 DATE_TRUNC('day', time) AS dt,
5 COUNT(*) AS block_count
6FROM ethereum."blocks"
7GROUP BY dt
8OFFSET 1
9
10# 每日产出区块的平均数量
11
12WITH temp_table AS (
13SELECT
14 DATE_TRUNC('day', time) AS dt,
15 COUNT(*) AS block_count
16FROM ethereum."blocks"
17GROUP BY dt
18OFFSET 1
19)
20SELECT
21 AVG(block_count) AS avg_block_count
22FROM temp_table
显示全部

自 2016 年以来,每日产出的平均区块数量为 5,874,略高于该估算值。 另外,将 86400 秒除以 5874 个平均区块数,得出 14.7 秒,即大约每 15 秒一个区块。

燃料

区块的大小是有限的。 最大区块大小是动态的,根据网络需求在 12,500,000 到 25,000,000 个单位之间变化。 需要设置限制,以防止任意大的区块给完整节点在磁盘空间和速度方面带来压力(来源)。

理解区块燃料限制的一种方法是,将其看作是可用于批量处理交易的区块空间的供应。 可以查询并可视化从 2016 年至今的区块燃料限制:

1SELECT
2 DATE_TRUNC('day', time) AS dt,
3 AVG(gas_limit) AS avg_block_gas_limit
4FROM ethereum."blocks"
5GROUP BY dt
6OFFSET 1

然后是每日实际使用的燃料,用于支付在以太坊链上完成的计算(即发送交易、调用智能合约、铸造 NFT)。 这是对以太坊可用区块空间的需求

1SELECT
2 DATE_TRUNC('day', time) AS dt,
3 AVG(gas_used) AS avg_block_gas_used
4FROM ethereum."blocks"
5GROUP BY dt
6OFFSET 1

我们还可以将这两个图表并列,看看需求和供应如何匹配:

gas_demand_supply

因此,在给定可用供应的情况下,我们可以将燃料价格理解为以太坊区块空间需求的函数。

最后,我们可能想查询以太坊链的日均燃料价格,但这样做会导致查询时间特别长,所以我们将筛选查询,只查询以太坊基金会为每笔交易支付的平均燃料量。

我们可以看到多年来,向以太坊基金会地址发起的交易所支付的燃料价格。 查询如下:

1SELECT
2 block_time,
3 gas_price / 1e9 AS gas_price_gwei,
4 value / 1e18 AS eth_sent
5FROM ethereum."transactions"
6WHERE "to" = '\xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'
7ORDER BY block_time DESC

总结

通过本教程,我们查询并感受了链上数据,从而了解了以太坊的基本概念以及以太坊区块链的工作原理。

包含本教程中所有代码的看板可以在此处opens in a new tab找到。

若要更多地使用数据来探索 Web3,请在 Twitteropens in a new tab 上找到我。

页面最后更新: 2025年9月29日

本教程对你有帮助吗?