区块链自问自答 day2
区块链自问自答 day2
区块链的自治性是如何达成的?为什么能够在去信任的环境下自由安全地交换数据?
区块链中有众多的节点,包含了恶意节点、故障节点、正常节点,想要这些节点共同做出一致的决定就需要一套共识机制来解决。
1982年,著名计算机学家兰波特提出了拜占庭将军问题:拜占庭帝国派出了几只军队进攻一个城堡,如果这些带队的将军中有叛徒,在只能靠信使通讯的情况下,如何能够保证忠诚的将军同时、准确的行动?这个问题本质是说:在分布式计算机网络中,如果存在故障和恶意节点,是否能够保持正常节点的网络一致性问题。在近40年的时间里,人们提出了许多方案解决这一问题,称为拜占庭容错法。例如兰波特自己提出了口头协议、书面协议法,后来有人提出了实用拜占庭容错PBFT算法,在2008年,中本聪发明比特币后,人们又设想了通过区块链的方法解决这一问题。
简要介绍一下什么是拜占庭将军问题(BFT,拜占庭容错)?
问题是有一个坚固的城堡,需要多位将军在不同地点(只能用信使进行通信)同时发起进攻才能沦陷它,那么需要采用什么样的方法,在存在将军叛徒的情况下,所有将军达成一致的决定去进攻城堡。
假设有7位将军在做决策,在不存在叛徒的情况下可以采用投票的方式进行决策,只要超过半数将军投票进攻那么就一起进攻,否则一起撤退,不会造成部分将军进攻部分将军撤退导致损失的情况。
但是如果7位将军中存在一位叛徒,在投票的时候出现了3:3的情况,这时叛徒就会告诉3位支持进攻的将军我支持进攻,而告诉另3位支持撤退的将军,我支持撤退。这样在3位支持进攻的将军眼中投票结果是4:3支持进攻的,在3位支持撤退的将军眼中是3:4支持撤退的。这样叛徒就成功的达成了它的目的,破坏了将军们决策的一致性和正确性。
BFT如何做到保持一致性和正确性?
-
将军-副官模型
设背叛者的数量为m,总将军数为n
问题要求:
- 所有忠诚的副官都遵守一个命令,即一致性。
- 若发令者是忠诚的,每一个忠诚的副官都遵守它发出的命令,即正确性。
-
口头协议
口头消息传递过程中默认的一些条件:
- 每个被发送的消息都能够被正确地投递。
- 信息接收者知道是谁发送的消息。
- 能够知道缺少的消息。
在这三个条件下就默认不会有背叛者截断消息,并且也不会有背叛者伪造他人信息。
假设有三位将军a、b、c,c是叛徒,a是发令者。a向b、c发送进攻命令,b因为不知道a是不是叛徒,接到a的命令后就向c询问它收到的是什么命令,c因为是叛徒,它就告诉b它收到的是撤退命令,这时b手上接到了进攻和撤退命令是1:1,b知道a和c之间肯定有一个是叛徒,但是不知道是谁,就无法执行a的命令。这样就无法达成一致的决定。
再假设有4位将军a、b、c、d,c是叛徒,a是发令者。a向b、c、d发送进攻命令,b因为不知道a是不是叛徒,他就问c、d收到的是什么命令,c因为是叛徒就告诉b接到的是撤退命令,d告诉b接到的是进攻命令。这时b手上接到的进攻和撤退命令是2:1,这时b就能确定了要执行进攻命令,同样d也收到进攻和撤退命令是2:1。这样a、b、d就达成了命令一致,并且正确的执行了a的命令。
所以在口头协议中要解决拜占庭问题就需要满足一个条件:如果有m个叛徒则将军的总数必须为3m+1以上。
-
书面消息
书面消息传递中需要口头协议中的三个条件并且追加一条:
- 签名不可被伪造,一旦被篡改即可发现;任何人都可以验证将军签名的可靠性。
在书面协议中每条命令发出和转发都会在后面带上发出和转发者的签名,每个将军手中都有一个集合用来保存收到命令种类(不是数量),当将军收到一条消息后,如果命令类型在自己的集合里没有就会把这个命令放进集合,并且如果这条命令还没被其他将军签名过,也会转发出去给别的将军。直到所有将军不再接到新消息后,判断将军手里的集合,如果集合一致那么就会作出一致的选择。
结论:在书面消息的方式中,一定可以让忠诚的将军达成一致,但是结果不一定正确。
比特币系统是如何运作的?
当Alice要向Bob转账时,她先从自己的钱包当中找到付款地址的私钥,使用这个私钥对这笔交易进行一次签名,证明这笔交易是Alice自己发起的。通过非对称加密算法,网络上的任何人都可以使用公钥来对这笔交易进行验证,确实是属于Alice的。
Alice所使用的钱包是一种文件,可以让用户访问多个比特币地址。每一个地址是一串由字母和数字组成的字符串。每一个地址都有自己的比特币余额。
Bob在接收Alice的付款是需要生成一个收款地址,生成一个地址其实是生成一个密钥对,由一个私钥和公钥组成。私钥由自己保存,不能给别人看,公钥可以给所有人看,Bob的收款地址对应了一个唯一的公钥,私钥则保存在Bob的钱包里。
比特币用户可以任意创建多个地址,并且鼓励为每一个新的交易单独创建新地址,以增强隐私性。只要没有人知道哪些地址是Bob的,他的匿名性就受到保护。
Alice提交的交易会被矿工打包成一个新的交易区块,这个区块当中包含了过去10 min之内的交易。矿工的工作就是计算加密散列函数。矿工的计算机基于前一个区块的散列值、新交易区块和随机数,来计算新的散列值。因为前一个区块的散列值和新交易区块的散列值都是不变的,只有随机数可以变化,所以矿工为了达到散列值的格式要求(必须以特定数量的0作为开始),要不停的生成随机数再计算散列值直到满足要求。
成功生成区块后,Alice给Bob的转账就被存到了区块链当中,在每一个区块中都会有一笔叫Coinbase的初始交易,这是给挖出区块的矿工的奖励。任何人想要更改历史交易的细节,就必须再重做一遍胜出矿工的工作,然后再重做下一级区块的胜出矿工的工作,计算量会非常巨大所以这样的操作基本是不可能的。
总的来说比特币的系统分六个部分:
- 钱包和地址
- 新建地址
- 私钥和公钥
- 提交支付
- 验证交易
- 交易确认
钱包地址是如何生成的?
-
使用随机数(256 bit)作为私钥,需要安全地保存。
-
通过SECP256K1算法生成带有前缀的公钥(512 bit)
secp256k1是由(Standards for Efficient Cryptography)定制的一种椭圆曲线签名算法,在比特币流行以前,该算法几乎没有被使用过。大多数常用的曲线具有一个随机的结构,但是secp256k1是为了更有效率的计算而构造了一个非随机结构。因此如果该算法的实现通过合理的优化,其计算效率可以比别的曲线快30%以上。同时,与常用的NIST曲线不同,secp256k1的常量是通过可预测的方式挑选的,这可以有效的减少防止曲线设计者安置后门的可能性。
-
再使用SHA256算法把公钥变成256 bit的散列字符串,后使用RIPEMD(RACE Integrity Primitives Evaluation Message Digest)算法RIPEMD160把256 bit的散列值变成160 bit的散列字符串
RIPEMD-160是以原始版RIPEMD所改进的160位元版本,而且是RIPEMD系列中最常见的版本。 RIPEMD-160是设计给学术社群所使用的,刚好相对于国家安全局 所设计SHA-1和SHA-2算法。 另一方面,RIPEMD-160比SHA-1较少使用,所以可能造成RIPEMD-160比SHA还不常被审查。另外,RIPEMD-160并没有任何专利所限制。
-
最后使用Base58 Check对公钥进行编码,形成可读的字符串地址
Base58编码是Base64编码的子集,去掉了0(数字)、O(大写字母)、l(小写字母)、I(大写字母)以及“+”和“/”符号。
Base58 Check流程:
-
在公钥散列的头部连接版本号(对于比特币网络的pubkey地址,这一字节为“0”),形成“0x00+公钥散列”
-
对“0x00+公钥散列”进行double-SHA256处理后取前4bit
-
将取出的前4bit作为地址信息的校验码,放到公钥散列的后面形成“0x00+公钥散列+校验码”
-
将“0x00+公钥散列+校验码”送入Base58编码形成人类易读的字符串地址,钱包地址
-
比特币系统有哪些优点和缺点?
比特币系统有以下几个有点。
- 无须第三方的介入,降低了交易成本,同时使整个P2P网络具有对等性。
- 比特币的安全基于SHA256加密算法,目前还无有效的破解方式。所有的比特币交易都在网络上公开,便于大家达成共识,并能有效防止非法活动。比特币的产生和认证机制也使它不可能被伪造。
- 部分匿名性,交易的主要元素是钱包、地址,用户全程处于匿名状态。之所以说部分匿名性,是由于所有交易都公布在网上,所有人都可以看到。结合大数据对其分析,很有可能推测出某些用户的真实身份。
- 比特币供应有限,无通胀之虞。比特币系统的设计有点仿照黄金供应,其上限数量为2100万个,可以有效防止央行滥发导致的通货膨胀。
同时,比特币也有一些缺点,如下。
- 交易确认时间过长。10 min产生一个块,一般认为等待6个块后可以确认交易不可逆。这样,确认一笔交易要等待1 h,这么大的时间成本是不容忽视的。因此,现在一些小额交易都采取零确认支付的形式。
- 区块容量。完全节点有个硬性的物理尺寸限制(即每个区块最大1 MB),所以,每10 min产生1 MB的区块,除以每笔交易记录的平均尺寸,可以得出当前的限制大概是每秒7笔交易,每天600000笔交易。当交易量达到这个阈值时,没来得及确认的交易会延长确认时间。
- 区块链图灵性差。比特币中的区块链合约简单,不具备自由变成为智能合约的能力。为解决此问题,区块链2.0的代表以太坊应运而生。
- 单一的工作量证明机制。比特币上的工作量证明机制是基于全网51%以上的算力都是诚实的。但如果某些集团可以联合达到51%以上的算力,对比特币系统发动攻击理论上也是可行的。
比特币中的P2P网络如何组建的?
运行比特币P2P协议的比特币著网络由7000~10000个运行着不同版本比特币核心客户端的监听节点以及几百个运行着各类比特币P2P协议应用(如BitcoinJ、Libbitcoin、btcd等)的节点组成。比特币P2P网络中的一部分节点是挖矿节点,它们竞争挖矿、验证交易并创建新的区块。许多连接到比特币网络的大型公司运行着基于Bitcoin核心客户端的全节点客户端,它们具有区块链的完整复制及网络节点,但不具备挖矿及钱包功能。这些节点是网络中的边缘路由器,通过它们可以搭建其他服务,如交易所、钱包、区块浏览器、商家支付处理(Merchant Payment Processing)等。
比特币中的网络结构不包括地理信息,因此节点间的地理信息完全无关。
节点连接过程:
-
一般使用8333端口建立TCP连接
-
新节点通过发送一条包含基本认证内容的version消息开始“握手”
消息包括:
- P2P协议版本(PROTOCOL_VERSION)
- 本节点支持的本地服务列表(nLocalServices)
- 当前时间(nTime)
- 对方节点IP地址(addrYou)
- 本节点IP地址(addrMe)
- 比特币软件版本(subver)
- 本节点当前区块链的区块高度(BassHeight)
-
对等节点通过对verack消息的响应进行确认并建立连接,如果接收节点需要互换连接并连回起始节点,也会传回该对等节点的version消息
-
发现节点过程:
方法一:
使用种子节点(Seed Node),比特币客户端会维持一个包含长期稳定节点的列表,称之为种子节点。通常比特币核心带有5个不同的种子节点,但是并不一定要与种子节点进行连接,用户可以自行设置开启与关闭也可以提供一个固定IP地址列表来进行替换。使用种子节点可以快速的发现网络中的其他节点。
方法二:
通过一个已知节点作为种子节点发现其他邻节点。当新节点发现新的邻节点后,新节点一般将断开和种子节点的连接。新节点把自己地址信息传给邻节点,邻节点再把传来的地址信息发送给它的邻节点,使新节点的地址被网络中的其他节点发现。
新节点也会发送给邻节点一个getaddr信息,邻节点将把自己的已知地址信息发给新节点。新节点一般维持与8个邻节点的连接。新节点启动流程结束后将记住发现的邻节点地址信息,再次启动时如果地址信息都失效将重新开始启动流程。
-
在节点之间建立连接后会定期的发送信息保持连接状态。如果节点与一个邻节点的连接在超过90min中没有联系,默认该邻节点下线,寻找新的邻节点与之连接。