



比特币核心实现了一个JSON-RPC接口,它也可以通过命令行助手bitcoin-cli来访问。命令行使我们能够与通过API编程方式提供的类似功能进行交互式实验。首先,调用help命令来查看可用的比特币核心RPC命令列表:
这些命令中的每一个都可能需要多个参数。要获取额外的帮助、详细描述和有关参数的信息,请在help后面加上命令名。例如,要查看getblockhash RPC命令的帮助信息:
在帮助信息的末尾,你将看到两个示例,一个使用bitcoin-cli,另外一个使用HTTP终端命令curl的RPC命令示例。这些示例展示了如何调用该命令。复制第一个示例并查看结果:
输出的结果是一个区块的哈希值,在后续章节中将有更详细的描述。但就目前而言,此命令在你的系统上应该返回相同的结果,证明你的比特币核心节点正在运行,可以接收命令,并将第1000个区块的信息反馈给你。
接下来我们将展示一些非常有用的RPC命令及其预期的输出。
比特币核心通过JSON-RPC接口提供不同模块的状态报告。最重要的命令包括getblockchaininfo、getmempoolinfo、getnetworkinfo和getwalletinfo。
比特币的getblockchaininfo RPC命令最早被引入。getnetworkinfo命令显示有关比特币网络节点状态的基本信息。使用bitcoin-cli来运行它:
数据以JavaScript对象表示法(JavaScript Object Notation,JSON)的形式返回,这种格式不仅可以被所有编程语言轻松解读,而且对人类来说也相当易读。在这些数据中,我们可以看到比特币核心软件和比特币协议的版本号。我们还可以看到当前的连接数量、有关比特币网络的各种信息,以及与该节点相关的设置。
可能需要一些时间,或许超过一天,才能让bitcoind追上当前的区块链高度,因为它需要从其他比特币节点下载区块并验证区块中的每一笔交易——截至本书撰写时已近十亿笔交易。你可以使用getblockchaininfo命令来检查其进度,查看已知区块的数量。本章的其余示例假设你至少已经同步到区块775072。由于比特币交易的安全性依赖于区块,因此随着你的节点拥有的区块数量不同,接下来例子中的一些信息也会稍有变化。
在2.2节中,Alice在Bob的商店中进行了一笔购物交易。她的交易被记录在区块链上。我们使用API来检索并查看那笔交易,方法是将交易ID(txid)作为参数传递:
交易ID(txid)并不是生成之后固定不变的。区块链中缺少txid并不表示交易没有被处理。这被称为“交易可延展性”,因为交易在被确认进入区块之前可以被修改,从而改变它们的txid。一旦交易被纳入区块,它的txid就不会改变,除非区块链发生了重组,即该区块被从最优(通常是最长)区块链中移除。当一笔交易获得几次确认之后,重组的情况是非常罕见的。
命令getrawtransaction会返回以十六进制表示的序列化交易数据。要解码这些数据,我们使用decoderawtransaction命令,并将十六进制数据作为参数传入。你可以复制getrawtransaction返回的十六进制数据,并将其粘贴为decoderawtransaction命令的参数:
交易解码显示了这笔交易的所有组成部分,包括交易的输入和输出。在这个例子中,我们看到交易使用了一个输入,并生成了两个输出。这笔交易的输入来自之前已确认交易的输出(显示为输入的txid)。两个输出对应于支付给Bob以及找零退回给Alice。
我们可以通过使用相同的命令(例如getrawtransaction),查找由此交易中的txid引用的前一笔交易,通过不断从一个交易跳转到另一个交易,我们可以追溯一连串的交易链,观察如何将比特币从一个所有者传递到下一个所有者。
探索区块与探索交易类似。然而,可以通过区块高度或区块哈希进行区块查找。首先,让我们通过区块高度找到一个区块。我们使用getblockhash命令,该命令以区块高度作为参数,返回该区块的区块头哈希值:
现在我们知道了所选区块的区块头哈希值,我们就可以查询这个区块。我们使用getblock命令,并将区块哈希值作为参数:
确认数目(confirmations)标记此区块的深度——叠加在此区块上的区块数量,这表示更改此区块中的任何交易的难度。高度(height)则告诉我们在这个区块之前有多少区块。我们可以看到区块的版本号、创建时间(根据矿工确定)、前11个区块的中位时间(这是一个较难被矿工篡改的时间指标),以及以三种不同方式量度的区块大小(传统过滤后大小、完整大小以及以权重单位计的大小)。我们还可以看到一些用于安全与工作量证明的字段(默克尔树、随机数、难度位、难度和链工作量),这些内容我们将在第12章中详细探讨。
bitcoin-cli客户端非常方便我们探索与测试比特币核心的API。但API的更大意义在于以编程方式访问函数。在本节中,我们将演示如何利用程序访问比特币核心。
比特币核心的API是一个JSON-RPC接口。JSON是一种非常便捷的数据表示方式,它既适合人类阅读又便于程序识别。RPC代表远程过程调用,这意味着我们可通过HTTP网络协议调用那些远程的(位于比特币核心节点上的)过程(函数)。
当我们使用bitcoin-cli命令来获取某个命令的帮助信息时,它展示了使用curl这个功能强大的命令行HTTP客户端来构建JSON-RPC调用的一个例子:
该命令展示了curl向本地主机(127.0.0.1)提交了一个HTTP请求,连接到默认的比特币RPC端口(8332),并使用text/plain编码提交了一个针对getblockchaininfo方法的jsonrpc请求。
你可能会注意到curl会要求将凭证与请求一起发送。比特币核心将在每次启动时创建一个随机密码,并将其放在名为.cookie的数据目录中。bitcoin-cli帮助程序可以根据数据目录读取此密码文件。同样,你可以复制密码并将其传递给curl(或任何更高级别的比特币核心RPC包装器),如示例3-3所示。
示例3-3:在比特币核心中使用基于Cookie的认证方法
或者,你可以使用位于比特币核心源代码目录 ./share/rpcauth/rpcauth.py 中的辅助脚本来创建一个静态密码。
如果你在自己的程序中实现一个JSON-RPC调用,那么你可以使用一个通用的HTTP库来构造调用,类似于前面展示的curl示例。
然而,在大多数流行的编程语言中,都有库能够“封装”比特币核心API,使得这一切变得更加简单。我们将使用python-bitcoinlib库来简化API访问。这个库不是比特币核心项目的一部分,需要通过安装Python库的常规方式来安装。另外,你需要有一个运行中的比特币核心实例,它将被用于JSON-RPC调用。
示例3-4中的Python脚本执行了一个简单的getblockchaininfo调用,并输出了比特币核心返回数据中的区块参数。
示例3-4:通过比特币核心的JSON-RPC API执行getblockchaininfo命令
执行后得到如下结果:
它告诉我们本地比特币核心节点在其区块链中有多少个区块。虽然结果并不让人眼前一亮,但它展示了该库作为比特币核心JSON-RPC API的简化接口的基本用途。
接下来,我们使用getrawtransaction和decodetransaction命令调用来检索Alice支付给Bob的交易详情。在示例3-5中,我们检索了Alice的交易,并列出了交易的输出。对于每一个输出,我们展示了接收者的地址和数额。友情提示,Alice的交易包含一个支付给Bob的输出和一个找零退回Alice的输出。
示例3-5:检索交易并迭代其输出
执行这段代码,我们将得到:
前面的两个示例都相当简单,它们并不真正需要一个程序来运行,你完全可以直接使用bitcoin-cli工具。然而,示例3-6需要数百次RPC调用,更清晰地展示了编程接口的使用优势。
在示例3-6中,我们首先检索一个区块,然后通过交易ID检索区块中的每笔交易。接下来,我们遍历每笔交易的输出并累加其价值。
示例3-6:检索一个区块并累加所有交易输出
执行这段代码,我们将得到:
我们的示例代码计算出,在这个区块中交易的总金额是10322.07722534比特币(包括25比特币的奖励和0.0909比特币的交易手续费)。可以与在区块链浏览器网站通过搜索区块哈希值或区块高度找到的汇总金额相比较。看看你能否发现其中的差异,有些区块链浏览器的汇总金额不包括奖励和交易手续费。