一、比特币协议与实现

从技术角度看,比特币是一种数字加密货币协议,它仅仅约定了在比特币网络中 节点旳行为规范,因此任何人都可以遵照此规范实现自己的比特币节点软件并接入 比特币网络。如果你希望深入了解比特币协议,可以查看 这里

容易理解,在现有的诸多实现中,最著名的就是最早由中本聪本人发起的 BitcoinCore项目:

BitcoinCore被称为比特币协议的参考实现,这意味着它给出了比特币协议的每 一部分应当如何实现的权威参考或者说范本,因此在本课程中将基于该软件学习比特币的使用 和应用开发。课程环境中预置了BitcoinCore软件,如果你需要在自己的机器上 练习,可以从官方网站下载。

在BitcoinCore项目中,包含了两个完整的比特币协议实现:图形版的bitcoin-qt和 命令行版的bitcoind,我们称之为节点软件。这两个软件的作用是一致的, 在本课程在线环境中将使用bitcoind来部署比特币节点:

部署在不同计算机上的节点软件可以彼此联通成一个复杂的P2P网络,进而实现 比特币交易的中继、广播与确认,因此是整个比特币网络的核心。

节点软件通常也提供基于JSON RPC的API接口,以便其他应用集成对比特币区块链 的访问能力。在BitcoinCore项目中的bitcoin-cli软件就是一个基于节点RPC API的 命令行工具,我们将使用这个工具来学习比特币的一些常用操作。

二、节点软件与客户端

节点软件是比特币网络的核心,因此在继续下面的课程之前,我们先在1# 终端启动节点软件bitcoind:~$ bitcoind

在1#终端按Ctrl+C就可以结束bitcoind的运行,或者在2#终端,使用 pkill命令结束:~$ pkill bitcoind

如果希望将区块链清零,可以在停止bitoind的运行后,删除整个数据目录, 然后重新启动

~$ pkill bitcoind

~$ rm -rf ~/.bitcoin/regtest

~$ bitcoind

配置节点软件

bitcoind的运行依赖于其配置文件,在ubuntu中,该文件的路径为~/.bitcoin/bitcoin.conf

对于一个新部署的bitcoind节点,首先需要修改的是RPC API的访问控制, 下面的设定将允许客户端以用户user和密码123456来访问RPC API接口:

rpcuser=user

rpcpassword=123456

bitcoind有三种运行模式,可以分别连接到主链、测试链或构建一个单节点 的私有链用于开发。在本课程中,我们将其运行模式设置为私有链模式:

regtest=1

使用客户端工具

节点软件bitcoind实现了完整的比特币规范,但是它没有提供人机操作接口, 因此我们需要借助于bitcoin-cli这个命令行工具来访问节点软件提供的功能。

例如,可以使用getbalance子命令来获取节点钱包余额:

注意:如果没有执行过其他的操作,你看到的余额应该是0.00000000

bitcoin-cli的子命令对应于节点旳JSON RPC开发接口,可以完成地址创建、 交易发送、余额查询、区块浏览等诸多任务。

三、身份:密钥与地址

比特币的身份识别体系是建立在非对称加密技术之上的去中心化系统, 每一个身份对应着一对密钥。

非对称加密采用一对密钥(私钥、公钥)进行数据的加密或解密: 用私钥加密,则需要用公钥解密;用公钥加密,则需要用私钥解密。 这一非对称特性使得其非常适合用于身份表示与验证 —— 公钥用于 身份的表示,而私钥则用于身份的验证:

在上图中,当tommy需要向jerry发送原始数据时,他首先使用自己的私钥对 原始数据进行签名,得到的签名数据附加在原始数据后面,一同发送给jerry。 jerry收到数据后,使用tommy的公钥就可以验证签名是否是由tommy的私钥签发的, 从而确认该数据确实来自于tommy。

虽然公钥可以唯一的标识一个身份,但在比特币中更多的使用地址来 标识身份,可以认为地址是一个或一组公钥的精简表示,因此同样可以 使用私钥进行验证:

使用getnewaddress调用可以生成并返回一个新的地址,例如:

~$ bitcoin-cli getnewaddress
2NC6QeGFjxyBb1qqYq5wz3UyufQ4cMMVz7S

使用validateaddress调用可以查看这个地址的相关信息,例如公钥:

~$ bitcoin-cli validateaddress 2NC6QeGFjxyBb1qqYq5wz3UyufQ4cMMVz7S    
{
  "isvalid": true, 
  "address": "2NC6QeGFjxyBb1qqYq5wz3UyufQ4cMMVz7S", 
  ...
  "pubkey": "02c865c914ee88ac798e66e0623012286c1549c709a4f8efa994a1504f180574f5", 
    ...
}

使用dumpprivkey调用可以导出这个地址的私钥:

~$ bitcoin-cli dumpprivkey 2NC6QeGFjxyBb1qqYq5wz3UyufQ4cMMVz7S    
cNvFMEshrc7oNaoPwFgygmpwzM7xt1DAtvD5xh5uogQZuoMk7S4v

dumpprivkey命令导出的私钥是经过base58编码的WIF格式(Wallet Import Format), 该格式主要用于私钥的拷贝黏贴,并且很容易转换回原始格式。

这样看起来,是不是意味着 从地址可以推导出私钥和公钥?

希望上面的操作不要误导了你,bitcoind只是在节点钱包里保存了地址和 密钥的对应关系而已,任何情况下你都无法从地址反向推导出公钥,或者从 公钥反向推导出私钥。

#!/bin/bash

addr=`bitcoin-cli getnewaddress`
echo  "address => $addr"

pub=`bitcoin-cli validateaddress $addr | jq '.pubkey' | sed s/\"//g`
echo "public key => $pub"

prv=`bitcoin-cli dumpprivkey $addr`
echo "private key => $prv"

四、节点钱包

节点软件bitcoind除了完整实现比特币的核心协议,还包含了一个可选但是重要 的功能模块 —— 钱包:

可以把钱包视为保存着你所有密钥与地址的保险箱,同时也封装了比特币很多 偏技术性的概念与细节,使其可以被极客之外的人群所理解和接受。因此在默认 配置下,bitcoind会启用节点钱包。如果你希望禁止钱包功能,例如你准备自己 管理密钥与地址,那么可以在配置文件中设置disablewallet选项:

disablewallet=1

钱包模块会跟踪其管理的所有地址相关的交易,因此可以及时地更新钱包的余额信息。 这一功能非常重要,因为比特币中没有账户的概念,比特币是散落在一个个交易 中的电子现金,如果没有钱包帮助跟踪与我们地址相关的交易,那么想算清楚自己 总共持有多少个比特币都很困难。

节点提供的很多RPC调用都是由钱包模块来实现的。例如,当我们调用getnewaddress 命令时,就是由钱包模块来生成密钥和地址并自动加入到钱包中, 因此其相关的交易也会自动地影响钱包的余额。同样,当我们调用getbalance时, 也是由钱包模块来汇总所有地址上的比特币并返回总金额。

五、挖矿:交易确认与激励

我们知道,比特币是通过挖矿这种机制来保证分布式环境下的节点一致性, 只有通过挖矿,交易才能在众多节点之间达成共识并最终打包到区块中上链。

在另一方面,挖矿也是比特币系统的造币机制,所有的比特币都是通过各个 节点的挖矿出块产生的,并且支付给矿工作为其付出的奖励 —— 这一奖励最初 是50个比特币,并且每出21万个区块之后减半,直至最终减少到0。目前阶段的挖矿 奖励是每区块12.5个比特币。

节点挖矿获得的奖励并不会立刻生效,而必须等待更多的区块生成之后才可用。 这是因为当比特币网络中出现分叉时,某些区块会变成孤儿,而这些区块包含的交易 将被重新打包入其他区块,同时这些孤儿区块的挖矿奖励将被回收:

因此按照约定,挖块奖励得到的比特币必须要等101个确认(Confirms)之后才能生效。

执行挖矿操作

在公链上我们没什么机会挖矿,不过在私链上,必须由自己挖矿,否则交易 没有办法确认。

使用generate调用来执行挖矿操作,例如下面的命令连续挖出101个区块:

~$ bitcoin-cli generate 101

generate命令也是由钱包模块实现的,它会创建一个新的钱包地址,然后将挖矿奖励转入 这个新地址。显然在第N+100个块挖出后,第N个块的确认达到了101个,因此第N块 的奖励就生效了。现在看一下我们的钱包余额:

~$ bitcoin-cli getbalance

你应该看到余额有了变换。

六、比特币转账交易

钱包有了余额,我们就可以尝试给其他地址转比特币了:

由于bitcoind内置了钱包模块,转账交易变得非常简单:只要调用sendtoaddress接口就可以向指定的地址发送比特币了。

我们先使用getnewaddress调用来生成一个新地址以便测试:

~$ bitcoin-cli getnewaddress
2MzJkG1a4ZfWt3v3d3Rmkv57Z7UyLDHpep5

然后使用sendtoaddress`命令就可以向这个新地址转账了。 例如,下面的代码向我们新生成的地址转入2.45个比特币并返回交易id:

~$ bitcoin-cli sendtoaddress 2MzJkG1a4ZfWt3v3d3Rmkv57Z7UyLDHpep5 2.45

现在我们挖矿确认这个交易,给它6次确认:

~$ bitcoin-cli generate 6

需要指出的是,由于getnewaddress生成的地址是自动添加到钱包中的, 因此该地址收到的比特币依然计入到钱包的余额中。

使用getreceivedbyaddress调用查看地址接收到的比特币数量:

~$ bitcoin-cli getreivedbyaddress 2MzJkG1a4ZfWt3v3d3Rmkv57Z7UyLDHpep5 6
2.45000000
#!/bin/bash

addr=`bitcoin-cli getnewaddress`
echo "address => $addr"

txid=`bitcoin-cli sendtoaddress $addr 2.45`
echo "txid => $txid"

blks=`bitcoin-cli generate 6`
echo "mined 6 block"

received=`bitcoin-cli getreceivedbyaddress $addr 6`
echo "received  => $received"

七、理解交易的结构

交易(Transaction)是比特币的核心,它不仅是比特币流转的记录,而且 比特币本身也隐含在交易当中。下图表示了两个交易之间比特币的流转过程:

通常一个交易总是包含输入(vin)和输出(vout)两个部分,其中的输入 用来引用其他交易的输出。但用来记录挖矿奖励的币基交易/coinbase transaction 是个例外:它只有输出部分。例如,上图中的交易1111是一个币基交易,其 输出部分记录了挖矿奖励的50个币转入了地址x。

交易2222则记录了地址x的持有者向地址y转40个币的事实。在这个交易 的输入部分,可以看到它引用了交易1111的第0个输出,就是说,将把交易 1111的第0个输出所表示的比特币转给地址y。

交易输出在没有被其他交易使用之前,被称为未消费交易输出/Unspent Transaction Output, 简称为UTXO。UTXO的一个重要特点是不可以拆分消费:要么不使用它,要么完全使用它。 这有点像现钞:你不能把一张50元的钞票撕成40元和10元。 因此,虽然只需要给地址y转40个比特币,但是交易1111中的这个面值50个币的UTXO 会完全消耗掉,不再可用。

交易的输入总额与输出总额的差值,就是支付给矿工的交易费/Transaction Fee。 因此对于上面的交易我们还需要构造第二个交易输出来处理多出来的10个比特币,只把 其中一小部分支付交易费,剩下的使用x持有人控制的另一个地址z来回收 —— 就 像找零钱一样,因此这个地址z通常被称为找零地址/change address。当然,也 可以将这部分比特币转给另一个外部地址。

当交易2222被确认后,交易1111的第0个输出就被消耗掉了,不再可用;产生 的两个新的UTXO,则分别属于地址y和地址z,而这一事实,被记录在 交易2222中写入区块链。

我们可以使用如下的命令来创建、确认一个转账交易:

~$ addr=`bitcoin-cli getnewaddress`
~$ txid=`bitcoin-cli sendtoaddress $addr 3.33`
~$ blks=`bitcoin-cli generate 6`

然后使用getrawtransaction调用来查看交易的详情:

~$ bitcoin-cli getrawtransaction $txid true

当指定参数true时,返回的结果是解码后的JSON格式的交易详情,其 vin字段中包含本次交易使用的所有前序UTXO,这些UTXO在交易确认后就 不再是UTXO了:

在vout字段中则包含本次交易生成的新的UTXO:

#!/bin/bash

addr=`bitcoin-cli getnewaddress`
echo "address => $addr"

txid=`bitcoin-cli sendtoaddress $addr 3.33`
echo "txid => $txid"

blks=`bitcoin-cli generate 6`
echo "mined 6 blocks"

bitcoin-cli getrawtransaction $txid true

今天新书的CIP号也下来了,把书demo的代码也刚发给了编辑,希望本周能下厂,坐等新书了,感兴趣的小伙伴到时候可以支持一下。

 

版权声明:本文为5ishare原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/5ishare/p/10933215.html