比特币核心客户端实现了一个可供命令行助手bitcoin-cli调用的JSON-RPC接口。这使我们可以实验那些通常由程序通过API调用的功能。开始前,我们先调用help命令来看一下全部可用的RPC命令列表:
比特币的getinfo RPC命令显示比特币网络节点、钱包、区块链数据库状态的基础信息,运行bitcoin-cli:
数据以JavaScript对象符号(JSON)格式返回,这种格式不仅容易被编程语言“消费”,也便于人工阅读。在数据中,我们可以看到比特币客户端的版本号(90000),协议版本号(70002),钱包版本号(60000),也能看到钱包的余额,当前为0。还能看到区块高度,告诉我们客户端总共看到了多少区块(当前286216)。另外,返回信息中还包含各种比特币网络相关的统计数据,以及当前客户端相关的设置信息。我们将在本章剩余部分更详细地了解这些设置。
在开始创建密钥和其他命令前,你需要首先利用密码来给钱包加密。在这个例子中,我们使用encryptwallet命令和密码“foo”,显然用更加强大和复杂的密码替代“foo”是必须的!
你可以重新运行getinfo来检查钱包是否已经加密。这次,你会注意到有个新的条目叫unlocked_until。这是一个计数器,显示钱包解密密码在内存中存储、保持钱包解锁状态的时间。最初,计数器会被设为0,代表钱包是被锁定的:
为了解锁钱包,发出walletpassphrase命令,它包含两个参数——密码、直到钱包重新锁定的超时秒数(时间计数器):
你可以重新运行getinfo确认钱包是否已解锁并获取超时时间:
接下来,我们练习创建钱包备份文件,然后从备份文件中恢复钱包。使用backupwallet命令来备份,提供文件名作为命令的参数。这里,我们将钱包备份到文件wallet.backup中:
现在,利用importwallet从备份文件中恢复钱包。如果钱包是锁定状态的,你需要先进行解锁(在上一节可以查看walletpassphrase命令用法)。
dumpwallet命令用于将钱包导出为可读的文本文件:
比特币标准客户端维护着一个地址池,地址池的大小在命令getinfo的输出项keypoolsize中展示。这些地址是自动生成的,可作为公开的接收地址或者找零地址。使用getnewaddress命令,可以生成一个新地址:
现在,我们可以从外部钱包(假设你在交易所、网络钱包或者在其他地方运行的bitcoind钱包中已经拥有一些比特币),通过这个地址发送一笔小额的比特币到我们的bitcoind钱包。在这个例子中,我们将发送50毫比特(0.050比特币)到这个地址。
我们可以通过bitcoind客户端查询此地址已经接收到的比特币金额。查询时,需要指定确认次数,即经过多少次确认一笔资金才会计入余额中,在这里,我们指定0次确认。从另一个钱包发送比特币几秒后,我们就可以看到,交易已经在钱包的余额中体现了。现在,我们使用getreceivedbyaddress命令并结合地址及确认次数0来查看:
如果省略掉命令最后一个0,我们将只能看到经过至少minconf次确认的金额,minconf是最少确认次数的设置值,未达到这个确认次数,交易不会计入余额。minconf的值是在bitcoind配置文件中设置的。因为发送这个比特币的交易仅仅发生在几秒前,它尚未被确认,所以我们看到它只列出了一个0余额:
钱包接收到的所有交易也可以利用listtransactions命令列出来:
我们还可以利用getaddressesbyaccount命令列出钱包中的所有地址:
最后,命令getbalance可以显示钱包的全部余额,命令会自动合并所有经过至少minconf次确认的交易金额。
现在,我们来看看前面利用gettransaction命令列出的传入交易。我们可以通过交易哈希提取到一笔交易,交易哈希就是前面我们看到的txid,提取交易的命令为:gettransaction。
通过命令gettransaction显示的交易形式是一种简化的形式。为了获取完整交易的代码并解码它,我们需要利用两个命令:getrawtransaction和decoderawtransaction。首先,使用命令getrawtransaction,并以交易哈希(txid)作为参数,将返回一个“原始”的十六进制字符串,就像它在比特币网络上的样子。
为了解码这个十六进制字符串,需要使用decoderawtransaction命令。复制粘贴这些十六进制代码作为命令decoderawtransaction的第一个参数,就得到了完整的以JSON数据格式表示的内容(出于排版格式需要,十六进制字符串在以下例子中被截短了):
这个JSON格式的输出展示了一个交易的所有组成元素,包括交易输入和输出。在这个例子中,我们看到交易使用了一个输入并生成了两个输出,在我们的新地址记入了50毫比特。这个交易的输入是上一笔已确认交易的输出(显示为vin下d3c7开始的txid)。两个输出一笔是50毫比特的入账,另一笔是交易找零。
我们可以使用同样的命令(如gettransaction),通过查看txid引用的交易,进一步对区块链进行探索。如此一级一级循着交易链条,我们可以看到资金一次又一次地从一个所有者地址转移到另一个所有者地址。
如果接收到的交易已经被确认,gettransaction命令还将额外返回交易所在区块的区块哈希(标识符):
在这里,我们看到输出项中多了一个blockhash条目(区块哈希,交易所在区块的哈希值)和值为18的blockindex条目(区块索引,指此交易是区块内的第18个交易)
默认情况下,比特币核心创建一个仅包含与用户钱包相关的交易数据库。如果你希望访问任何类似gettransaction等命令能查看的交易,你需要配置比特币核心,使其创建一个完整的交易索引。这可以通过设置txindex选项来实现。在比特币核心的配置文件(该文件通常位于你的Home目录下的.bitcoin/ bitcoin.conf)中设置txindex=1。一旦你修改了参数,你需要重启bitcoind并等待其完成索引创建。
现在我们已经知道交易位于哪个区块内,我们可以查询该区块。使用getblock命令并以区块哈希作为参数:
区块包含367个交易,你可以看到,第18个交易(9ca8f9...)是往我们的地址上发送50毫比特的交易ID(txid)。输出项高度(height)告诉我们这是区块链中的第286384个区块。
我们也可以利用getblockhash命令,根据区块的高度来获取区块信息。这种情况下,我们使用区块高度作为参数,返回区块哈希:
这里,我们取得了“创世区块”的哈希,它是中本聪挖到的第一个区块,其高度为0。进一步获取区块的详细信息如下:
getblock、getblockhash,以及gettransaction命令也可用于程序中查询区块链数据库。
比特币的交易基于花费“输出”的概念,“输出”是前序交易的结果,由此创建了一个在所有者地址间的价值传递的交易链。我们的钱包软件现在接收到了一个交易,它将一个输出分配给我们的地址。一旦这个交易被确认,我们就能花费这个输出。
首先:我们利用listunspent命令来显示我们钱包中未花费的已确认交易输出:
我们看到交易9ca8f9...创建了一个输出(vout索引号为0),为地址1hvzSo...存入50毫比特,此时该交易已经经过7次确认。交易使用前序交易创建的输出作为它的输入,通过引用前序交易的txid和vout索引形成与前序交易的连接。我们现在可以创建一个新的交易来花费txid为9ca8f9...的第0个输出(vout=0),在这个交易中,我们将把上述交易的输出作为新交易的输入,并将它发给一个新的地址。
首先,我们更细致地了解一下这个交易的输出。我们使用gettxout来获取这个未花费输出。交易输出总是通过txid和vout被引用,这也是我们传给gettxout的参数:
我们在此看到的是给我们的地址1hvz...发送50毫比特的交易输出。为了花费这个输出,我们将创建一笔新交易。首先,我们生成一个新的地址用于接收资金:
我们将发送25毫比特到这个新创建的地址(1LnfTn...)。在新交易中,我们将花费50毫比特的输出,并且发送25毫比特到这个新地址。由于我们必须花费前序交易的整个输出,所以交易还会产生一部分找零。我们将找零发送回原地址(1hvz...)。最后,我们还需要支付一些交易费用。为了发送费用,我们把找零的数额减少0.5毫比特,仅找回24.5毫比特。交易输出的总额为(25mBTC+24.5mBTC=49.5mBTC)与输入(50mBTC)的差额,将会作为交易费用被矿工收集走。
我们使用createrawtransaction来创建这个交易。作为参数,我们提供交易输入(已确认交易的50毫比特未花费输出),以及两个交易输出(发往新地址的资金和返回发送者自身地址的交易找零):
createrawtransaction命令产生一串原始十六进制字符串,将我们提供的交易细节进行编码。接下来,我们使用decoderawtransaction命令解码这串字符串,来确认一下所有事情是不是已经正确完成。
看起来像是正确的!新交易“花费”了我们已确认交易中的未花费输出,并将其拆分为两个输出:一个是25毫比特,发到我们新地址;另一个24.5毫比特作为交易找零返回原地址。0.5毫比特的差额作为交易费用,将发给找到包含本交易区块的矿工。
就像你可能注意到的那样,交易中包含一个空的scriptSig(脚本签名),因为我们尚未对其签名。如果没有签名,那么一笔交易是毫无意义的,因为尚未证明我们拥有未花费输出的地址。通过签名,我们移除了输出的限制,证明了我们确实拥有这笔输出,并且能够使用它。我们使用signrawtransaction命令来签名交易,它以原始交易的十六进制字符串作为参数。
signrawtransaction命令将另外一个十六进制编码的原始交易返回。我们将其解码之后看看有什么变化:
现在,交易中的输入包含了scriptSig,这是一个地址(1hvz...)拥有者提供的数字签名,解除了原交易输出的限制,输出得以使用。签名使交易可以被比特币网络上的任何节点进行确认。
是时候将这个新交易提交到网络中去了。我们使用sendrawtransaction命令,该命令以上述已签名交易的原始十六进制字符串作为参数,也就是刚刚我们解码的字符串。
当交易提交到网络后,sendrawtransaction命令返回一个交易哈希(txid)。我们可以利用gettransaction命令来查询这个交易ID:
就像之前看到的,我们依然可以使用getrawtransaction和decodetransaction命令查看更详细的信息。它们返回的信息与交易提交网络之前看到的是一样的。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。