第三章 Bitcoin Core 参考实现

  • berry
  • 发布于 2025-02-06 15:48
  • 阅读 25

综合介绍

在人们接受货币以换取他们宝贵的商品和服务时,他们相信自己将来能够使用这笔钱。如果货币是伪造的或者意外地贬值,那么这笔钱未来可能无法使用,因此每个接受比特币的人都有强烈的动机来验证他们收到的比特币的完整性。比特币系统被设计成,完全在您本地计算机上运行的软件可以完美地防止伪造、贬值和其他几个关键问题。提供该功能的软件称为完整验证节点,因为它会对系统中的每个已确认的比特币交易根据每条规则进行验证。完整验证节点,简称为完整节点,还可以提供了解比特币工作原理和当前网络状况的工具和数据。

在本章中,我们将安装比特币核心(Bitcoin Core),这是自比特币网络建立以来大多数完整节点操作员使用的实现。然后,我们将检查来自您节点的区块、交易和其他数据,这些数据是权威性的——不是因为某个强大的实体指定了它,而是因为您的节点独立验证了它。在本书的其余部分,我们将继续使用比特币核心来创建和检查与区块链和网络相关的数据。

从比特币到比特币核心

比特币是一个开源项目,其源代码可在开放(MIT)许可下获取,可供任何目的免费下载和使用。比仅仅是开源,比特币是由一个开放的志愿者社区开发的。起初,该社区只包括中本聪(Satoshi Nakamoto)。到2023年,比特币的源代码已经有了1000多名贡献者,其中大约有十几名开发人员全职工作在代码上,还有几十名在兼职基础上工作。任何人都可以为代码做出贡献——包括您!

当中本聪创建比特币时,软件在白皮书(见附录A)发布之前就已经基本完成了。中本聪希望在发表关于它的论文之前确保实现的可行性。那个最初的实现,当时简称为“比特币”,已经被大幅修改和改进。它已经演变成了我们所知的比特币核心,以区别于其他实现。比特币核心是比特币系统的参考实现,这意味着它提供了如何实现技术的参考。比特币核心实现了比特币的所有方面,包括钱包、交易和区块验证引擎、区块构建工具以及比特币点对点通信的所有现代部分。 图3-1显示了比特币核心的架构。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/3.1.png" alt=""><figcaption><p>图 3-1. 比特币核心架构</p></figcaption></figure>

虽然比特币核心作为系统的许多主要部分的参考实现,但比特币白皮书描述了系统的几个早期部分。自2011年以来,系统的大部分重要部分都已在一组比特币改进提案(BIPs)中进行了记录。在本书中,我们通过它们的编号引用BIP规范;例如,BIP9描述了用于几个重要的比特币升级的机制。

比特币开发环境

如果您是一名开发人员,您将希望建立一个开发环境,其中包括编写比特币应用程序所需的所有工具、库和支持软件。在这一高度技术的章节中,我们将逐步介绍这个过程。如果材料变得过于密集(而且您实际上并没有建立开发环境),请随时跳到下一章,那里的内容不那么技术性。

编译比特币核心的源代码

比特币核心的源代码可以通过下载存档文件或从GitHub克隆源代码存储库来获取。在比特币核心下载页面上,选择最新版本并下载源代码的压缩存档。或者,使用Git命令行从GitHub的比特币页面创建源代码的本地副本。

{% hint style="info" %} 在本章的许多示例中,我们将使用操作系统的命令行界面(也称为“shell”),通过“终端”应用程序访问。Shell会显示一个提示符,您输入一个命令,Shell会用一些文本和一个新的提示符来回应您的下一个命令。提示符在您的系统上可能看起来不同,但在以下示例中,它用$符号表示。在示例中,当您看到$符号后面的文本时,不要输入$符号,而是直接输入紧随其后的命令,然后按Enter执行该命令。在示例中,每个命令下面的行是操作系统对该命令的响应。当您看到下一个$前缀时,您会知道这是一个新命令,您应该重复这个过程。 {% endhint %}

这里,我们使用git命令创建源代码的本地副本(“克隆”):

$git clone https://github.com/bitcoin/bitcoin.git&#x20;

Cloning into 'bitcoin'...&#x20;

remote: Enumerating objects: 245912, done.&#x20;

remote: Counting objects: 100% (3/3), done.&#x20;

remote: Compressing objects: 100% (2/2), done.&#x20;

remote: Total 245912 (delta 1), reused 2 (delta 1), pack-reused 245909

Receiving objects: 100% (245912/245912), 217.74 MiB | 13.05 MiB/s, done.&#x20;

Resolving deltas: 100% (175649/175649), done.

{% hint style="info" %} Git是最广泛使用的分布式版本控制系统,是任何软件开发人员工具包的必备部分。如果您尚未安装git命令或Git的图形用户界面,则可能需要在您的操作系统上安装它。 {% endhint %}

当Git克隆操作完成后,您将在名为bitcoin的目录中拥有完整的源代码存储库的本地副本。使用cd命令切换到此目录:

$cd bitcoin

选择比特币核心版本

默认情况下,本地副本将与最新的代码同步,这可能是比特币的一个不稳定或测试版本。在编译代码之前,请通过检出一个发布标签来选择一个特定版本。这将会将本地副本与代码存储库的特定快照同步,该快照由关键标签标识。标签被开发人员用于按版本号标记代码的特定发布。首先,要查找可用的标签,我们使用git tag命令:

$ git tag

v0.1.5

v0.1.6test1

v0.10.0

...

v0.11.2

v0.11.2rc1

v0.12.0rc1

v0.12.0rc2

...

标签列表显示了所有已发布的比特币版本。按照惯例,用于测试的预发布候选版本后缀为“rc”。可以在生产系统上运行的稳定版本没有后缀。从上述列表中选择最高版本的发布版本,在撰写本文时为v24.0.1。要将本地代码与此版本同步,请使用git checkout命令:

$ git checkout v24.0.1

Note: switching to 'v24.0.1'.

You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by switching back to a branch.

HEAD is now at b3f866a8d Merge bitcoin/bitcoin#26647: 24.0.1 final changes

您可以通过输入git status命令来确认您已经“检出”了所需的版本:

HEAD detached at v24.0.1

nothing to commit, working tree clean

配置比特币核心构建

源代码包括文档,可以在许多文件中找到。查看位于bitcoin目录中的README.md中的主要文档。在本章中,我们将在Linux上构建比特币核心守护进程(服务器),也称为bitcoind(类Unix系统)。通过阅读doc/build-unix.md上的指南来审阅有关在您的平台上编译bitcoind命令行客户端的说明。备用说明可在doc目录中找到;例如,Windows说明可在build-windows.md中找到。截至撰写本文时,Android、FreeBSD、NetBSD、OpenBSD、macOS(OSX)、Unix和Windows的说明均可用。

仔细查看构建文档的第一部分,其中包含构建先决条件。这些是必须在您的系统上存在的库,然后您才能开始编译比特币。如果这些先决条件缺失,构建过程将失败并显示错误。如果由于您遗漏了某些先决条件而导致此问题,则可以安装它,然后从中断处恢复构建过程。假设已安装了先决条件,则可以通过使用autogen.sh脚本生成一组构建脚本来启动构建过程:

\ $ ./autogen.sh

libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, 'build-aux'.

libtoolize: copying file 'build-aux/ltmain.sh'

libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'build-aux/m4'.

...

configure.ac:58: installing 'build-aux/missing'

src/Makefile.am: installing 'build-aux/depcomp'

parallel-tests: installing 'build-aux/test-driver'

autogen.sh脚本创建一组自动配置脚本,将查询您的系统以发现正确的设置,并确保您具有编译代码所需的所有必要库。其中最重要的是configure脚本,它提供了许多不同的选项来定制构建过程。使用--help标志查看各种选项:

$ ./configure --help

`configure' configures Bitcoin Core 24.0.1 to adapt to many kinds of systems.

Usage: ./configure [OPTION]... [VAR=VALUE]...

...

Optional Features:

--disable-option-checking ignore unrecognized --enable/--with options

--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)

--enable-FEATURE[=ARG] include FEATURE [ARG=yes]

--enable-silent-rules less verbose build output (undo: "make V=1")

--disable-silent-rules verbose build output (undo: "make V=0")

...

configure脚本允许您通过--enable-FEATURE和--disable-FEATURE标志启用或禁用bitcoind的某些功能,其中FEATURE被替换为功能名称,如帮助输出中所列。在本章中,我们将使用所有默认功能构建bitcoind客户端。我们不会使用配置标志,但您应该查看它们以了解客户端的可选功能。如果您处于学术环境中,计算机实验室的限制可能要求您在您的主目录中安装应用程序(例如,使用--prefix=$HOME)。

以下是一些有用的选项,可以覆盖configure脚本的默认行为:

--prefix=$HOME

这将覆盖生成的可执行文件的默认安装位置(默认为/usr/local/)。使用$HOME将所有内容放在您的主目录中,或者使用其他路径。

--disable-wallet

这用于禁用参考钱包实现。

--with-incompatible-bdb

如果要构建钱包,则允许使用不兼容版本的 Berkeley DB 库。

--with-gui=no

不构建图形用户界面,这需要 Qt 库。这将仅构建服务器和命令行 Bitcoin Core。

\ 接下来,运行配置脚本,自动发现所有必要的库,并为您的系统创建一个定制的构建脚本:

\ $ ./configure

checking for pkg-config... /usr/bin/pkg-config

checking pkg-config is at least version 0.9.0... yes

checking build system type... x86_64-pc-linux-gnu

checking host system type... x86_64-pc-linux-gnu checking for a BSD-compatible install... /usr/bin/install -c

...

[many pages of configuration tests follow]

...

如果一切顺利,configure命令将结束,并创建定制的构建脚本,使我们能够编译bitcoind。如果存在任何缺少的库或错误,configure命令将以错误而不是创建构建脚本结束。如果出现错误,这很可能是由于缺少或不兼容的库引起的。再次查看构建文档,确保安装了缺少的先决条件,然后重新运行configure,看看是否解决了错误。\ \

构建比特币核心可执行文件

下一步,您将编译源代码,这个过程可能需要长达一小时才能完成,具体取决于您的CPU速度和可用内存。如果出现错误或编译过程中断,可以随时通过再次键入 make 来恢复。输入 make 开始编译可执行应用程序:

$ make

Making all in src

CXX bitcoind-bitcoind.o

CXX libbitcoin_node_a-addrdb.o

CXX libbitcoin_node_a-addrman.o

CXX libbitcoin_node_a-banman.o

CXX libbitcoin_node_a-blockencodings.o

CXX libbitcoin_node_a-blockfilter.o

[... many more compilation messages follow ...]\ \ 在性能较快且具有多个CPU的系统上,您可能希望设置并行编译作业的数量。例如,make -j 2 将使用两个可用的核心。如果一切顺利,比特币核心现在已经编译完成。您应该使用 make check 运行单元测试套件,以确保链接的库没有明显的问题。最后一步是使用 make install 命令在您的系统上安装各种可执行文件。由于此步骤需要管理员权限,因此您可能需要输入您的用户密码:

$ make check && sudo make install

Password:

Making install in src

../build-aux/install-sh -c -d '/usr/local/lib'

libtool: install: /usr/bin/install -c bitcoind /usr/local/bin/bitcoind

libtool: install: /usr/bin/install -c bitcoin-cli /usr/local/bin/bitcoin-cli

libtool: install: /usr/bin/install -c bitcoin-tx /usr/local/bin/bitcoin-tx

...

默认情况下,bitcoind 的安装位置是 /usr/local/bin。您可以通过询问系统执行文件的路径来确认 Bitcoin Core 是否正确安装,方法如下:

$ which bitcoind

/usr/local/bin/bitcoind

$ which bitcoin-cli

/usr/local/bin/bitcoin-cli

运行比特币核心节点

比特币的点对点网络由网络“节点”组成,主要由个人和提供比特币服务的一些企业运行。那些运行比特币节点的人可以直接且权威地查看比特币区块链,拥有自己系统独立验证的所有可消费比特币的本地副本。通过运行节点,您不必依赖任何第三方来验证交易。此外,通过使用比特币节点对您钱包收到的交易进行全面验证,您可以为比特币网络做出贡献,帮助使其更加强大。

然而,运行节点需要下载和处理超过 500 GB 的数据,以及每天约 400 MB 的比特币交易数据。这些数字是针对 2023 年的情况,并且随着时间的推移可能会增加。如果您关闭节点或者与互联网断开连接了几天,您的节点将需要下载错过的数据。例如,如果您关闭比特币核心 10 天,那么下次启动它时,您将需要下载约 4 GB 的数据。

取决于您是否选择索引所有交易并保留完整的区块链副本,您可能还需要大量的磁盘空间——如果您计划运行比特币核心数年,至少需要 1 TB 的磁盘空间。默认情况下,比特币节点还会将交易和区块传输给其他节点(称为“对等节点”),消耗上传互联网带宽。如果您的互联网连接受限,有低数据上限,或者是按千兆比特收费的,那么您可能不应该在其上运行比特币节点,或者以限制其带宽的方式运行它(请参阅“配置比特币核心节点”)。您可以将节点连接到其他网络,例如免费的卫星数据提供商,如 Blockstream Satellite。

{% hint style="info" %} 比特币核心默认会保留完整的区块链副本,其中包含自2009年以来比特币网络上几乎每笔确认交易的记录。这个数据集的大小达到数百GB,并且会根据您的CPU速度和互联网连接速度在几个小时或几天内逐步下载完成。在完整的区块链数据集下载完成之前,比特币核心将无法处理交易或更新账户余额。确保您有足够的磁盘空间、带宽和时间来完成初始同步。您可以配置比特币核心以减少区块链的大小,通过丢弃旧的区块,但它仍然会下载整个数据集。 {% endhint %}

尽管存在这些资源要求,成千上万的人都在运行比特币节点。有些人甚至在像树莓派(一台35美元的计算机,大小如一副牌)这样简单的系统上运行比特币节点。

你为什么想要运行一个节点呢?以下是一些最常见的原因:

  • 你不想依赖任何第三方来验证你接收到的交易。
  • 你不想向第三方披露哪些交易属于你的钱包。
  • 你正在开发比特币软件,并且需要依赖比特币节点进行对网络和区块链的可编程(API)访问。
  • 你正在构建必须根据比特币共识规则验证交易的应用程序。通常,比特币软件公司会运行多个节点。
  • 你想支持比特币。运行一个节点用于验证你接收到的钱包交易,可以使网络更加强大。

如果你正在阅读本书并对强大的安全性、优越的隐私性或开发比特币软件感兴趣,你应该运行自己的节点。

配置比特币核心节点

比特币核心在每次启动时都会在其数据目录中寻找配置文件。在本节中,我们将研究各种配置选项并设置一个配置文件。要查找配置文件,请在终端中运行bitcoind -printtoconsole,并查找前几行:

$ bitcoind -printtoconsole

2023-01-28T03:21:42Z Bitcoin Core version v24.0.1

2023-01-28T03:21:42Z Using the 'x86_shani(1way,2way)' SHA256 implementation

2023-01-28T03:21:42Z Using RdSeed as an additional entropy source

2023-01-28T03:21:42Z Using RdRand as an additional entropy source

2023-01-28T03:21:42Z Default data directory /home/harding/.bitcoin

2023-01-28T03:21:42Z Using data directory /home/harding/.bitcoin

2023-01-28T03:21:42Z Config file: /home/harding/.bitcoin/bitcoin.conf

...

[a lot more debug output]

...

\ 你可以按 Ctrl-C 关闭节点,一旦确定配置文件的位置。通常,配置文件位于用户的主目录下的 .bitcoin 数据目录中。用你喜欢的编辑器打开配置文件。Bitcoin Core 提供了100多个配置选项,可以修改网络节点的行为、区块链的存储以及其操作的许多其他方面。要查看这些选项的列表,请运行 bitcoind --help:

$ bitcoind --help

Bitcoin Core version v24.0.1

Usage: bitcoind [options] Start Bitcoin Core

Options:

-?

Print this help message and exit

-alertnotify=\<cmd>

Execute command when an alert is raised (%s in cmd is replaced by message)

...

[many more options]

以下是您可以在配置文件中设置的一些最重要的选项,或作为 bitcoind 的命令行参数:

alertnotify

运行指定的命令或脚本,向此节点的所有者发送紧急警报。

conf

配置文件的替代位置。这只有作为 bitcoind 的命令行参数才有意义,因为它不能在所指的配置文件内部。

datadir

选择存储所有区块链数据的目录和文件系统。默认情况下,这是您的主目录下的 .bitcoin 子目录。根据您的配置,到目前为止,这可能使用约 10 GB 到接近 1 TB 的空间,预计最大大小每年将增加数百 GB。

prune

通过删除旧的区块,将区块链磁盘空间要求减少到这么多兆字节。在资源受限的节点上使用此选项,无法容纳完整的区块链。系统的其他部分将使用其他磁盘空间,目前无法进行修剪,因此您仍然需要至少 datadir 选项中提到的最小空间量。\

txindex

维护所有交易的索引。这使您能够通过其ID以编程方式检索任何交易,前提是包含该交易的区块尚未被修剪。

dbcache

UTXO 缓存的大小。默认值为 450 Mebibytes(MiB)。在高端硬件上增加此大小,以减少磁盘读写次数,或者在低端硬件上减小大小,以节省内存,但会增加磁盘的使用频率。

blocksonly

通过仅接受经过确认的交易的区块,而不是中继未经确认的交易,来最大限度地减少带宽使用。

maxmempool

限制交易内存池到指定的兆字节数。这可用于减少内存受限节点上的内存使用。

{% hint style="info" %} 交易数据库索引和txindex选项

默认情况下,Bitcoin Core构建一个仅包含与用户钱包相关的交易的数据库。如果您想要能够使用诸如getrawtransaction(请参阅“探索和解码交易”)之类的命令访问任何交易,则需要配置Bitcoin Core以构建完整的交易索引,可以通过txindex选项实现。在Bitcoin Core配置文件中设置txindex=1。如果一开始没有设置此选项,而后来将其设置为完整索引,则需要等待其重建索引。 {% endhint %}

示例3-1 展示了如何将前面的选项与一个完全索引的节点结合起来,作为比特币应用程序的API后端运行。

示例3-1。完全索引节点的示例配置

alertnotify=myemailscript.sh "Alert: %s"

datadir=/lotsofspace/bitcoin

txindex=1

示例3-2 展示了在较小服务器上运行的资源受限节点的示例配置。

示例3-2。资源受限系统的示例配置

alertnotify=myemailscript.sh "Alert: %s"

blocksonly=1

prune=5000

dbcache=150

maxmempool=150\

在编辑配置文件并设置最符合您需求的选项后,您可以使用这个配置测试bitcoind。使用 printtoconsole 选项运行Bitcoin Core,以在前台输出到控制台:

$ bitcoind -printtoconsole

2023-01-28T03:43:39Z Bitcoin Core version v24.0.1

2023-01-28T03:43:39Z Using the 'x86_shani(1way,2way)' SHA256 implementation

2023-01-28T03:43:39Z Using RdSeed as an additional entropy source

2023-01-28T03:43:39Z Using RdRand as an additional entropy source

2023-01-28T03:43:39Z Default data directory /home/harding/.bitcoin

2023-01-28T03:43:39Z Using data directory /lotsofspace/bitcoin

2023-01-28T03:43:39Z Config file: /home/harding/.bitcoin/bitcoin.conf

2023-01-28T03:43:39Z Config file arg: [main] blockfilterindex="1"

2023-01-28T03:43:39Z Config file arg: [main] maxuploadtarget="1000"

2023-01-28T03:43:39Z Config file arg: [main] txindex="1"

2023-01-28T03:43:39Z Setting file arg: wallet = ["msig0"]

2023-01-28T03:43:39Z Command-line arg: printtoconsole=""

2023-01-28T03:43:39Z Using at most 125 automatic connections

2023-01-28T03:43:39Z Using 16 MiB out of 16 MiB requested for signature cache

2023-01-28T03:43:39Z Using 16 MiB out of 16 MiB requested for script execution

2023-01-28T03:43:39Z Script verification uses 3 additional threads

2023-01-28T03:43:39Z scheduler thread start

2023-01-28T03:43:39Z [http] creating work queue of depth 16

2023-01-28T03:43:39Z Using random cookie authentication.

2023-01-28T03:43:39Z Generated RPC cookie /lotsofspace/bitcoin/.cookie

2023-01-28T03:43:39Z [http] starting 4 worker threads

2023-01-28T03:43:39Z Using wallet directory /lotsofspace/bitcoin/wallets

2023-01-28T03:43:39Z init message: Verifying wallet(s)…

2023-01-28T03:43:39Z Using BerkeleyDB version Berkeley DB 4.8.30

2023-01-28T03:43:39Z Using /16 prefix for IP bucketing

2023-01-28T03:43:39Z init message: Loading P2P addresses…

2023-01-28T03:43:39Z Loaded 63866 addresses from peers.dat 114ms

[... more startup messages ...]

\ 您可以在满意加载了正确设置并且运行如您所期望的情况下,按下 Ctrl-C 来中断该过程。

要将Bitcoin Core作为后台进程运行,请使用守护进程选项启动它,例如 bitcoind -daemon

要监视您的Bitcoin节点的进度和运行时状态,请以守护进程模式启动它,然后使用命令 bitcoin-cli getblockchaininfo

$ bitcoin-cli getblockchaininfo

{
    "chain": "main",
    "blocks": 0,
    "headers": 83999,
    "bestblockhash": "[...]19d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
    "difficulty": 1,
    "time": 1673379796,
    "mediantime": 1231006505,
    "verificationprogress": 3.783041623201835e-09,
    "initialblockdownload": true,
    "chainwork": "[...]000000000000000000000000000000000000000000000100010001",
    "size_on_disk": 89087,
    "pruned": false,
    "warnings": ""
}

这显示了一个区块链高度为0个区块和83,999个头部的节点。节点首先从其对等节点获取块头,以找到具有最多工作量证明的区块链,然后继续下载完整的块,并在此过程中进行验证。

一旦您对所选择的配置选项感到满意,您应该将Bitcoin Core添加到操作系统的启动脚本中,以便它持续运行,并在操作系统重新启动时重新启动。您会在Bitcoin Core的源目录中的contrib/init下找到各种操作系统的示例启动脚本,以及一个README.md文件,显示哪个系统使用哪个脚本。

\ \ \

\

比特币核心 API

比特币核心 API 提供了一组命令,用于通过编程方式与运行中的比特币核心节点进行交互。这些命令可以通过 JSON-RPC 接口或使用 bitcoin-cli 命令行工具访问。以下是比特币核心 API 中常见的一些命令:

$ bitcoin-cli help

+== Blockchain ==

getbestblockhash

getblock "blockhash" ( verbosity )

getblockchaininfo

...

walletpassphrase "passphrase" timeout

walletpassphrasechange "oldpassphrase" "newpassphrase"

walletprocesspsbt "psbt" ( sign "sighashtype" bip32derivs finalize )

每个命令都可以接受多个参数。要获取更多帮助、详细描述以及有关参数的信息,请在 help 后面添加命令名称。例如,要查看关于 getblockhash RPC 命令的帮助:

$ bitcoin-cli help getblockhash

getblockhash height

Returns hash of block in best-block-chain at height provided.

Arguments:

  1. height (numeric, required) The height index

Result: "hex" (string) The block hash

Examples:

>bitcoin-cli getblockhash 1000

> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest",

"method": "getblockhash",

"params": [1000]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/

在帮助信息的末尾,你会看到两个RPC命令的示例,使用了bitcoin-cli助手或HTTP客户端curl。这些示例演示了如何调用该命令。复制第一个示例并查看结果:

$ bitcoin-cli getblockhash 1000 00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09

结果是一个区块哈希,在接下来的章节中将会详细介绍。但是目前,该命令应该在你的系统上返回相同的结果,表明你的Bitcoin Core节点正在运行,接受命令,并且有关于区块 1,000 的信息返回给你。

在接下来的章节中,我们将演示一些非常有用的RPC命令及其预期的输出。\

获取比特币核心状态信息

比特币核心通过 JSON-RPC 接口提供不同模块的状态报告。最重要的命令包括 getblockchaininfo、getmempoolinfo、getnetworkinfo 和 getwalletinfo。

比特币的 getblockchaininfo RPC 命令早已介绍过。getnetworkinfo 命令显示有关比特币网络节点状态的基本信息。使用 bitcoin-cli 运行它:

$ bitcoin-cli getnetworkinfo

{
    "version": 240001,
    "subversion": "/Satoshi:24.0.1/",
    "protocolversion": 70016,
    "localservices": "0000000000000409",
    "localservicesnames": [
        "NETWORK",
        "WITNESS",
        "NETWORK_LIMITED"
    ],
    "localrelay": true,
    "timeoffset": -1,
    "networkactive": true,
    "connections": 10,
    "connections_in": 0,
    "connections_out": 10,
    "networks": [
        "...detailed information about all networks..."
    ],
    "relayfee": 0.00001000,
    "incrementalfee": 0.00001000,
    "localaddresses": [],
    "warnings": ""
}

返回的数据采用 JavaScript 对象表示法(JSON)格式,这种格式可以轻松地被所有编程语言“消费”,但也非常易读。在这些数据中,我们看到比特币核心软件和比特币协议的版本号。我们还可以看到当前连接数以及有关比特币网络和与此节点相关的各种信息设置。

{% hint style="info" %} bitcoind 需要一些时间,也许超过一天的时间,来赶上当前的区块链高度,因为它要从其他比特币节点下载区块并验证这些区块中的每一笔交易 —— 在撰写本文时,这些交易已经接近 10 亿笔。您可以使用 getblockchaininfo 来检查其进度,以查看已知区块的数量。本章后续示例假定您至少已经到达了区块 775,072。因为比特币交易的安全性取决于区块,所以以下示例中的一些信息将根据您的节点有多少区块而略有变化 {% endhint %}

探索和解码交易

在“从在线商店购买”中,Alice从Bob的商店购买了商品。她的交易已记录在区块链上。让我们使用 API 通过传递交易ID(txid)作为参数来检索和检查该交易:

\ $ bitcoin-cli getrawtransaction 466200308696215bbc949d5141a49a41\\ 38ecdfdfaa2a8029c1f9bcecd1f96177

01000000000101eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da13569 8679268041c54a0100000000ffffffff02204e0000000000002251203b41daba 4c9ace578369740f15e5ec880c28279ee7f51b07dca69c7061e07068f8240100 000000001600147752c165ea7be772b2c0acb7f4d6047ae6f4768e0141cf5efe 2d8ef13ed0af21d4f4cb82422d6252d70324f6f4576b727b7d918e521c00b51b e739df2f899c49dc267c0ad280aca6dab0d2fa2b42a45182fc83e817130100000000

{% hint style="info" %} 交易ID(txid)并不具有权威性。在区块链中找不到txid并不意味着该交易未被处理。这被称为“交易可塑性”,因为在交易确认之前,交易可以被修改,从而改变其txid。一旦交易被包含在一个区块中,其txid就不能更改,除非发生了区块链重组,其中该区块从最佳区块链中被移除。在交易获得几个确认之后,区块链重组变得十分罕见。 {% endhint %}

命令getrawtransaction以十六进制表示返回一个序列化的交易。为了解码它,我们使用decoderawtransaction命令,并将十六进制数据作为参数传递。您可以复制getrawtransaction返回的十六进制数据,并将其粘贴为decoderawtransaction的参数:

$ bitcoin-cli decoderawtransaction 01000000000101eb3ae38f27191aa5f3850dc9cad0\ 0492b88b72404f9da135698679268041c54a0100000000ffffffff02204e00000000000022512\ 03b41daba4c9ace578369740f15e5ec880c28279ee7f51b07dca69c7061e07068f82401000000\ 00001600147752c165ea7be772b2c0acb7f4d6047ae6f4768e0141cf5efe2d8ef13ed0af21d4f\ 4cb82422d6252d70324f6f4576b727b7d918e521c00b51be739df2f899c49dc267c0ad280aca6\ dab0d2fa2b42a45182fc83e817130100000000

{
    "txid": "466200308696215bbc949d5141a49a4138ecdfdfaa2a8029c1f9bcecd1f96177",
    "hash": "f7cdbc7cf8b910d35cc69962e791138624e4eae7901010a6da4c02e7d238cdac",
    "version": 1,
    "size": 194,
    "vsize": 143,
    "weight": 569,
    "locktime": 0,
    "vin": [{
        "txid": "4ac541802679866935a19d4f40728bb89204d0cac90d85f3a51a19...aeb",
        "vout": 1,
        "scriptSig": {
            "asm": "",
            "hex": ""
        },
        "txinwitness": [
            "cf5efe2d8ef13ed0af21d4f4cb82422d6252d70324f6f4576b727b7d918e5...301"
        ],
        "sequence": 4294967295
    }],
    "vout": [{
            "value": 0.00020000,
            "n": 0,
            "scriptPubKey": {
                "asm": "1 3b41daba4c9ace578369740f15e5ec880c28279ee7f51b07dca...068",
                "desc": "rawtr(3b41daba4c9ace578369740f15e5ec880c28279ee7f51b...6ev",
                "hex": "51203b41daba4c9ace578369740f15e5ec880c28279ee7f51b07d...068",
                "address": "bc1p8dqa4wjvnt890qmfws83te0v3qxzsfu7ul63kp7u56w8q...5qn",
                "type": "witness_v1_taproot"
            }
        },
        {
            "value": 0.00075000,
            "n": 1,
            "scriptPubKey": {
                "asm": "0 7752c165ea7be772b2c0acb7f4d6047ae6f4768e",
                "desc": "addr(bc1qwafvze0200nh9vkq4jmlf4sy0tn0ga5w0zpkpg)#qq404gts",
                "hex": "00147752c165ea7be772b2c0acb7f4d6047ae6f4768e",
                "address": "bc1qwafvze0200nh9vkq4jmlf4sy0tn0ga5w0zpkpg",
                "type": "witness_v0_keyhash"
            }
        }
    ]
}

\ 交易解码显示了此交易的所有组件,包括交易输入和输出。在这种情况下,我们看到该交易使用了一个输入,并生成了两个输出。这笔交易的输入是来自先前确认的交易的输出(显示为输入txid)。这两个输出对应于付款给Bob和找零返回给Alice。

我们可以通过使用相同的命令(例如getrawtransaction)检查在此交易中引用其txid的先前交易来进一步探索区块链。从一笔交易跳转到另一笔交易,我们可以跟踪一系列交易,从而了解硬币是如何从一个所有者传递到下一个所有者的。

\

探索区块

探索区块与探索交易类似。然而,区块可以通过区块高度或区块哈希来引用。首先,让我们通过区块高度找到一个区块。我们使用getblockhash命令,该命令以区块高度作为参数,并返回该区块的区块头哈希:

$ bitcoin-cli getblockhash 123456

0000000000002917ed80650c6174aac8dfc46f5fe36480aaef682ff6cd83c3ca

现在我们知道了我们选择的区块的区块头哈希,我们可以查询该区块。我们使用getblock命令,并将区块哈希作为参数:

$ bitcoin-cli getblock 0000000000002917ed80650c6174aac8dfc46f5fe36480aaef682f\ f6cd83c3ca

{
    "hash": "0000000000002917ed80650c6174aac8dfc46f5fe36480aaef682ff6cd83c3ca",
    "confirmations": 651742,
    "height": 123456,
    "version": 1,
    "versionHex": "00000001",
    "merkleroot": "0e60651a9934e8f0decd1c[...]48fca0cd1c84a21ddfde95033762d86c",
    "time": 1305200806,
    "mediantime": 1305197900,
    "nonce": 2436437219,
    "bits": "1a6a93b3",
    "difficulty": 157416.4018436489,
    "chainwork": "[...]00000000000000000000000000000000000000541788211ac227bc",
    "nTx": 13,
    "previousblockhash": "[...]60bc96a44724fd72daf9b92cf8ad00510b5224c6253ac40095",
    "nextblockhash": "[...]00129f5f02be247070bf7334d3753e4ddee502780c2acaecec6d66",
    "strippedsize": 4179,
    "size": 4179,
    "weight": 16716,
    "tx": [
        "5b75086dafeede555fc8f9a810d8b10df57c46f9f176ccc3dd8d2fa20edd685b",
        "e3d0425ab346dd5b76f44c222a4bb5d16640a4247050ef82462ab17e229c83b4",
        "137d247eca8b99dee58e1e9232014183a5c5a9e338001a0109df32794cdcc92e",
        "5fd167f7b8c417e59106ef5acfe181b09d71b8353a61a55a2f01aa266af5412d",
        "60925f1948b71f429d514ead7ae7391e0edf965bf5a60331398dae24c6964774",
        "d4d5fc1529487527e9873256934dfb1e4cdcb39f4c0509577ca19bfad6c5d28f",
        "7b29d65e5018c56a33652085dbb13f2df39a1a9942bfe1f7e78e97919a6bdea2",
        "0b89e120efd0a4674c127a76ff5f7590ca304e6a064fbc51adffbd7ce3a3deef",
        "603f2044da9656084174cfb5812feaf510f862d3addcf70cacce3dc55dab446e",
        "9a4ed892b43a4df916a7a1213b78e83cd83f5695f635d535c94b2b65ffb144d3",
        "dda726e3dad9504dce5098dfab5064ecd4a7650bfe854bb2606da3152b60e427",
        "e46ea8b4d68719b65ead930f07f1f3804cb3701014f8e6d76c4bdbc390893b94",
        "864a102aeedf53dd9b2baab4eeb898c5083fde6141113e0606b664c41fe15e1f"
    ]
}

确认(confirmations)条目告诉我们这个区块的深度——有多少个区块是在其之上构建的,这表明改变该区块中任何交易的难度。高度告诉我们在该区块之前有多少个区块。我们看到了该区块的版本、创建时间(根据其矿工)、之前的11个区块的中位时间(对矿工来说更难以操纵的时间测量),以及区块的大小以三种不同的度量方式(其传统的剥离大小、完整大小和权重单位中的大小)。我们还看到了一些用于安全性和工作证明的字段(默克尔根、随机数、位、难度和链工作量);我们将在第12章中对这些进行详细探讨。

\

使用比特币核心的编程接口

比特币命令行助手 bitcoin-cli 对于探索比特币核心API和测试功能非常有用。但是,API的整个目的在于以编程方式访问函数。在本节中,我们将演示如何从另一个程序访问比特币核心。

\ 比特币核心的API是一个JSON-RPC接口。JSON是一种非常方便的数据呈现方式,可以让人类和程序都轻松读取。RPC代表远程过程调用,这意味着我们通过网络协议调用远程(位于比特币核心节点上的)过程(函数)。在这种情况下,网络协议是HTTP。

\ 当我们使用bitcoin-cli命令获取命令的帮助时,它向我们展示了使用curl的示例,这是一种功能多样的命令行HTTP客户端,用于构建这些JSON-RPC调用之一:

\ $ curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest",

"method": "getblockchaininfo",

"params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/

该命令显示了 curl 发送一个 HTTP 请求到本地主机 (127.0.0.1),连接到默认的比特币 RPC 端口 (8332),并使用纯文本编码提交一个 jsonrpc 请求,请求 getblockchaininfo 方法。

您可能会注意到 curl 会要求发送凭据以及请求一起发送。比特币核心在每次启动时会创建一个随机密码,并将其放置在数据目录下,命名为 .cookie。bitcoin-cli 辅助工具可以在给定数据目录的情况下读取此密码文件。类似地,您可以复制密码并将其传递给 curl (或任何更高级别的比特币核心 RPC 封装),如示例 3-3 所示。

示例 3-3. 使用基于 cookie 的身份验证与比特币核心

$ cat .bitcoin/.cookie cookie:17c9b71cef21b893e1a019f4bc071950c7942f49796ed061b274031b17b19cd0

$ curl --user cookie:17c9b71cef21b893e1a019f4bc071950c7942f49796ed061b274031b17b19cd0 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getblockchaininfo", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/

{"result":{"chain":"main","blocks":799278,"headers":799278, "bestblockhash":"000000000000000000018387c50988ec705a95d6f765b206b6629971e6978879", "difficulty":53911173001054.59,"time":1689703111,"mediantime":1689701260, "verificationprogress":0.9999979206082515,"initialblockdownload":false, "chainwork":"00000000000000000000000000000000000000004f3e111bf32bcb47f9dfad5b", "size_on_disk":563894577967,"pruned":false,"warnings":""},"error":null, "id":"curltest"}

或者,您可以使用 Bitcoin Core 源代码目录中提供的辅助脚本 ./share/rpcauth/rpcauth.py 创建一个静态密码。

如果您正在自己的程序中实现 JSON-RPC 调用,您可以使用通用的 HTTP 库来构建该调用,类似于前面的 curl 示例所示。

然而,大多数流行的编程语言都有库可以以更简单的方式“包装” Bitcoin Core API。我们将使用 python-bitcoinlib 库来简化 API 访问。该库不是 Bitcoin Core 项目的一部分,需要按照通常的 Python 库安装方式进行安装。 请记住,这需要您运行一个 Bitcoin Core 实例,该实例将用于进行 JSON-RPC 调用。

示例 3-4 中的 Python 脚本执行了一个简单的 getblockchaininfo 调用,并打印了 Bitcoin Core 返回数据中的块参数。

示例 3-4. 通过 Bitcoin Core 的 JSON-RPC API 运行 getblockchaininfo

from bitcoin.rpc import RawProxy
### Create a connection to local Bitcoin Core node
p = RawProxy()
### Run the getblockchaininfo command, store the resulting data in info
info = p.getblockchaininfo()
### Retrieve the 'blocks' element from the info
print(info['blocks'])

运行后,我们得到以下结果:

$ python rpc_example.py

773973

它告诉我们本地 Bitcoin Core 节点的区块链中有多少个区块。这并不是令人惊讶的结果,但它演示了使用该库作为简化接口访问 Bitcoin Core 的 JSON-RPC API 的基本用法。

接下来,让我们使用 getrawtransaction 和 decodetransaction 调用来检索 Alice 对 Bob 的付款的详细信息。在示例 3-5 中,我们检索 Alice 的交易并列出交易的输出。对于每个输出,我们显示接收者地址和价值。作为提醒,Alice 的交易有一个输出支付给 Bob,另一个输出是 Alice 的找零。

示例 3-5. 检索交易并迭代其输出

from bitcoin.rpc import RawProxy
p = RawProxy()
### Alice's transaction ID
txid = "466200308696215bbc949d5141a49a4138ecdfdfaa2a8029c1f9bcecd1f96177"
### First, retrieve the raw transaction in hex
raw_tx = p.getrawtransaction(txid)
### Decode the transaction hex into a JSON object
decoded_tx = p.decoderawtransaction(raw_tx)
### Retrieve each of the outputs from the transaction
for output in decoded_tx['vout']:
    print(output['scriptPubKey']['address'], output['value'])

运行此代码,我们得到:

$ python rpc_transaction.py bc1p8dqa4wjvnt890qmfws83te0v3qxzsfu7ul63kp7u56w8qc0qwp5qv995qn 0.00020000 bc1qwafvze0200nh9vkq4jmlf4sy0tn0ga5w0zpkpg 0.00075000

前面的两个例子都相当简单。你不真的需要一个程序来运行它们;你可以同样使用bitcoin-cli助手。然而,下一个例子需要几百个RPC调用,并更清晰地展示了编程接口的使用。

在示例3-6中,我们首先检索一个块,然后通过引用每个交易ID检索其中的每个交易。接下来,我们遍历每个交易的输出,并累加其值。

示例3-6。检索一个块并添加所有交易输出

<pre class="language-python"><code class="lang-python">from bitcoin.rpc import RawProxy

p = RawProxy()

The block height where Alice's transaction was recorded

blockheight = 775072

Get the block hash of the block at the given height

blockhash = p.getblockhash(blockheight)

Retrieve the block by its hash

block = p.getblock(blockhash)

Element tx contains the list of all transaction IDs in the block

transactions = block['tx']

block_value = 0

Iterate through each transaction ID in the block

for txid in transactions: tx_value = 0

Retrieve the raw transaction by ID

raw_tx = p.getrawtransaction(txid)

<strong> ### Decode the transaction </strong> decoded_tx = p.decoderawtransaction(raw_tx)

Iterate through each output in the transaction

for output in decoded_tx['vout']:
    ### Add up the value of each output
    tx_value = tx_value + output['value']
### Add the value of this transaction to the total
block_value = block_value + tx_value

print("Total value in block: ", block_value) </code></pre>

运行这段代码,我们得到:

\ $ python rpc_block.py

Total value in block: 10322.07722534

我们的示例代码计算出这个区块中的总交易价值为10,322.07722534 BTC(包括25 BTC的奖励和0.0909 BTC的手续费)。与通过搜索区块哈希或高度在区块浏览器网站上报告的金额进行比较。一些区块浏览器报告的总值不包括奖励和手续费。看看你能否发现差异。

\

不同语言客户端、库和工具包

在比特币生态系统中,有许多替代客户端、库、工具包甚至是完整的节点实现。这些实现采用了各种编程语言,为程序员提供了他们喜欢的编程语言的本机接口。

以下各节列出了一些最好的库、客户端和工具包,按照编程语言进行组织。

C/C++

Bitcoin Core

比特币的参考实现

JavaScript

bcoin

一个模块化且可扩展的带有 API 的全节点实现

Bitcore

由 Bitpay 提供的全节点、API 和库

BitcoinJS

一个纯 JavaScript 的 Bitcoin 库,适用于 node.js 和浏览器

Java

bitcoinj

一个 Java 完整节点客户端库

Python

python-bitcoinlib

一个由Peter Todd提供的Python比特币库、共识库和节点

pycoin

由Richard Kiss提供的Python比特币库

Go

btcd

Go语言全节点比特币客户端

Rust

rust-bitcoin

Rust比特币库,用于序列化、解析和API调用

Scala

bitcoin-s

一个用Scala实现的比特币实现

C\

NBitcoin

.NET框架的综合比特币库

总结

\ 许多其他编程语言中还存在许多其他库,而且会有更多库不断被创建。

如果你按照本章的说明进行操作,现在你已经运行了比特币核心,并且已经开始使用你自己的全节点探索网络和区块链。从现在开始,你可以独立使用你控制的软件——在你控制的计算机上——验证你收到的任何比特币是否遵循比特币系统中的每条规则,而无需信任任何外部权威机构。在接下来的章节中,我们将更多地了解系统的规则,以及你的节点和钱包如何利用它们来保护你的资金安全,保护你的隐私,并使支出和接收更加方便。

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论