区块链学习笔记(二)- bitcoin-cli

242 阅读11分钟
原文链接: zhuanlan.zhihu.com

熟悉bitcoin-cli命令

我们已经见到了如何使用bitcoin-cli stop命令来安全地停止bitcoin core的运行。这一节,我们将介绍bitcoin-cli的命令分组,以及一些用以获取概览信息的命令。在本书的其它章节,你可能还会遇到更多的bitcoin-cli命令,比如如何查看某个具体的区块信息的命令。截止0.15版本,所有的命令可以通过文末的Bitcoin-cli命令速查表来查看。

下面所列的命令,都要通过bitcoin-cli来执行。

1.1 getblockchaininfo

这个命令用来显示比特币网络概览。输出如下所示:

{
"chain": "test",
"blocks": 0,
"headers": 32000,
"bestblockhash":
"000000000933ea01ad0ee9…f408719526f8d77f4943",
"difficulty": 1,
"mediantime": 1296688602,
"verificationprogress": 5.853850457214259e-08,
"chainwork":
"0000000000000000000…00000000000000100010001",
"pruned": false,
"softforks": [
{
"id": "bip34",
"version": 2,
"reject": {
"status": false
}
},
…
],
"bip9_softforks": {
"csv": {
"status": "defined",
"startTime": 1456790400,
"timeout": 1493596800,
"since": 0
 },
"segwit": {
"status": "defined",
"startTime": 1462060800,
"timeout": 1493596800,
"since": 0
}
}
}

为使格式美观,我们省略了部分输出,如bestblockhash字段原本有64位,我们省略了其中22位,改用“…”来代替。现在我们来简要地查看各个输出字段的含义:

Chain: 这个字段表明当前的区块链网络类型。总共有三种,在BIP70[7]中规定,一种是main,也就是大多数人正在使用的,可以运行普通交易的区块链网络,另一个是regtest。我们这里得到的是test,它用以研发人员进行测试。这里输出字段为test,表明我们在配置文件(bitcoin.conf)中设置了testnet = 1,如下图所示:

Blocks: 当前节点已处理的区块。这里的处理包括下载和验证 。在新安装的节点上,因为要做初次区块下载6,这个数值会一直增长,直到与全网同步。

Headers:当前结点已处理的区块头信息。这个数值也就是当前区块的高度值(height),可以从http://blockchain.info[8]上查到。这是我查询的结果:

在一个Full Node上,Headers与Blocks数值应该一致,但对新安装节点例外。新安装的节点上headers同步似乎会率先完成,而blocks的完全同步在我的环境中则等待了近1.5天。

题外话:比特币区块应该每10分钟产生一个。从上图可以看到,最近几个比特币区块只花了比较少的时间就被“挖掘”出来了。

Bestblockhash:当前最可信区块的ID,即当前最长链的最后一个有效区块。它可能是被挖掘出来的最新块,也可能不是—这取决于被挖掘出来的最新块是否在正确的分叉上。

Difficulty: 当前块的难度值。详细解释见2.1Difficulty和target bits。

Mediantime: 过去11个区块的中值时间。注意这里引用的区块是最长链上已确认的区块。这个时间是unix timestamp,即从1970年1月1日起计时。你可以在Linux机器上使用下面的命令将其转换为可读性更好的时间表示:

date -d @timestamp

在上述示例中,mediantime是1296688602,它对应着的时间是:

date -d @1296688602
--输出—
2011年 02月 03日 星期四 07:16:42 CST
成文时间时,mainnet上的mediantime是1517704544,它对应着的时间是:
date -d @1517704544
--输出—
2018年 02月 04日 星期日 08:35:44 CST

每个区块都包含着一个unix time时间戳。只有当这个时间戳大于mediantime,并且小于某个调整后的网络时间[1]时,这个区块才会被确认。

Verificationprogress: 已确认的交易占比,取值在0~1之间,也有可能略微大于1。在一个新安装的Full Node上,由于区块首先要下载完成才能进行确认,而确认时间较快,所以可以把这个比例当成区块下载完成进度。

Chainwork: 当这个字段出现在block中时,是指从创世块到当前块共进行了多少次double hash运算;当出现在getblockchaininfo的返回中时,是指当前链条共进行了多少次double hash运算。它是一个hex编码字符串,用来再分叉的链条间比较谁是最长链。在成文时间时,mainnet上的chainwork值是00000000000000000000000000000000000000000106796908bc47b48f4a67bf[2],相当于10进制的317311908621044699095525311,即 ,也即31.73 yotta。

Pruned:布尔值。表明当前是否处于pruned模式。如果处于pruned模式,则下载的区块可以被删除以节省磁盘空间。

剩下的信息是关于bitcoin分叉的,这一节我们先省略,以免引入过多的细节。

1.2 getwalletinfo

查看钱包的概要信息。

{ 
"walletname": "wallet.dat", 
"walletversion": 139900, 
"balance": 0.00000000, 
"unconfirmed_balance": 0.00000000, 
"immature_balance": 0.00000000, 
"txcount": 0, 
"keypoololdest": 1517455171, 
"keypoolsize": 1000, 
"keypoolsize_hd_internal": 1000, 
"unlocked_until":0, 
"paytxfee": 0.00000000, 
"hdmasterkeyid":
"57bb0019c214ab1e6accf211ec8c252157db965d"
}

多数字段的含义不言自明。这里仅对部分字段作简要的解释。

Balance是已确认的账户余额,使用BTC单位。

Unconfirmed_balance,支付到该钱包,但尚未确认的交易的总额,也是BTC单位。

Immatrue balance挖矿奖励金额需要等待100次确认后才能使用,在此之前,这部分金额都是immature状态。同样是BTC单位。

Txcount是指钱包里涉及的交易总个数。

Keypoololdest是指最早生成的key的unix时间戳。

Keypoolsize: 允许预先生成的公钥、私钥对的个数。使用多个可替换的公钥

私钥参与交易的目的是提升安全性和反跟踪。

keypoolsize_hd_internal, 用于内部使用(如找零)的钱包地址个数。

unlocked_until,钱包本身也可以加密,但在使用前必须解密。这个参数指明了解密后的钱包还能保持解密状态到何时。0表示钱包已上锁,其它数字应解释为Unix时间戳。

Hdmasterkeyid,HD wallets钱包seed key的160位Hash.

1.1.3 getnetworkinfo

这个命令用来查看当前节点的网络状况。包括节点使用的网络协议版本,当前网络是否在线(networkactive),有多少个连接(connections),以及使用了何种网络(ipv4,
ipv6及onion)。

前面所说的连接即peer connection,可以通过另一个命令getpeerinfo来查看。如果你执行下面的命令:

bitcoin-cli getpeerinfo |grep id |wc -l

你会得到与你建立了连接的节点数,这个数字应该等于我们通过getnetworkinfo所得到的连接数(connections).

1.1.4 getblockhash

这是一个十分重要的命令。我们知道,每个区块是通过其id来标识的,每个id都是一个160位的hash。这个id非常不方便交流。同时我们知道,每一个区块都有一个高度值,而对于主链来说,每一个高度值都对应着惟一一个区块。

我们可以通过这个命令来查找创世块、第一个区块(由中本聪在赫尔辛基的一个服务器上挖出)和其它任意高度的区块的id,并进而得到该区块的信息。

bitcoin-cli getblockhash 0
bitcoin-cli getblockhash 1
bitcoin-cli getblockhash 10000
---输出—
000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048
0000000099c744455f58e6c6e98b671e1bf7f37346bfd4cf5d0274ad8ee660cb

1.1.5 getblock

在得到了块的ID之后,可以通过getblock命令进一步查询它的信息:

bitcoin-cli getblock 000000000019d668985a…a2a6c172b3f1b60a8ce26f

我们由此得到创世块的信息:

{ 
"hash":
"000000000019d6689c085ae16…e46a2a6c172b3f1b60a8ce26f", 
"confirmations":
507548, 
"strippedsize":
285, 
"size": 285,  
"weight":
1140, 
"height": 0, 
"version": 1, 
"versionHex":
"00000001", 
"merkleroot":
"4a5e1e4baab89f3a32518a…cc77ab2127b7afdeda33b", 
"tx": [ 
"4a5e1e4baab89f3a32518a88c31bc…7ab2127b7afdeda33b" 
], 
"time": 1231006505, 
"mediantime":
1231006505, 
"nonce":
2083236893, 
"bits":
"1d00ffff", 
"difficulty":
1, 
"chainwork":
"0000000000000000…0000000000000000000100010001", 
"nextblockhash":
"00000000839ad76f4…0947ee320161bbf18eb6048" 
}

这样得到的信息并不包含交易信息,也即我们得到的是区块的头。要得到全部的信息,需要传入verbosity参数,当参数值为2时,即可得到全部信息:

bitcoin-cli getblock 000000000019d668985a…a2a6c172b3f1b60a8ce26f2
--输出—
略

上面的输出信息中有一些字段需要解释一下。

Hash: 区块的id,256字节的hash,hex编码。

Confirmations: 该区块已经过多少次确认。如果该区块属于best chain,则此值等于全链高度,也是本块的深度。

Size: 本块的大小。

Weight: 含义见BIP141。

Mediantime: 这个字段的含义在前面解释过了,我们感兴趣的是它的值的含义。这个时间decode出来是2009年的1月3日,一个周六(按GMT时间)。

这里的merkleroot、nonce、difficulty、bits可以说是比特币的核心,我们在后面专门讲解。

要理解我们这样得到的输出并不是原始块的数据,有些数据甚至并不存在于原始块当中,而是计算出来的,比如confirmations,nextblockhash等,它们的出现是为了帮助我们更好地理解这个区块。何以见得原始块并不包含这些数据呢?原来,getblock的verbosity参数共有三个取值,默认为1,我们已经见到何时使用2。而剩下的一个取值0,则可以帮我们dump出原始数据(以hex编码,当然!)。下面显示了创始块的原始数据,为了阅读方便起见,我并没有使用getblock的原始输出,而是使用了下面的格式:

这个输出值得好好解释一下。

前4个字节, 01000000,是版本号。

字节5到字节36,是前一个区块的hash,这里为零。

字节37到68,是当前块的merkle root hash。

字节69到72,29AB5F49,是区块挖出的时间,即2009年1月3日。注意这里需要调整字节序,实际的表示应该为0x495FAB29,即十进制的1231006505。

Header信息到Bits和Nonce结束,其后是跟交易相关的信息。我们放在专门的章节来讲。

现在,我们已经完全安装好了一个Full Node,并熟悉了它的设置和基本命令。这给了我们一个很好的探测和理解比特币网络的工具。接下来我们将从比特币交易开始,讲到区块的生成和确认,从而将最主要的比特币活动经历一次。

在理解交易之前,我们必须理解比特币钱包和钱包地址。


杨勇:区块链学习笔记(一)- 客户端安装zhuanlan.zhihu.com图标杨勇:区块链学习笔记(二)- bitcoin-clizhuanlan.zhihu.com图标杨勇:区块链学习笔记(三)-比特币钱包和地址zhuanlan.zhihu.com图标

[1] 这个时间是你当前连接的所有p2p结点传入的时间戳的中值再加上2小时。

[2] 对于这么大的数字的运算,可以借助python的decimal包。