构建去中心化的货币系统
我们假设央行要发行数字货币,很直观的是参考现金的发行形式,现金的特征是:
- 防伪标记: 难以伪造,不可篡改
- 唯一性:无法复制
如果要实现数字货币的防伪标记,那么基于公私钥体系就能很容易的实现,发行100元需要通过央行的私钥进行签名,公钥是公开的,任何人都可以验证它的权威性。公私钥保证了不可篡改,但没有解决货币的唯一性,毕竟代码本身就是文件,是可以无限复制的。
如果数字货币可以无限复制,就容易产生双花攻击,即被央行发行的一个货币被多次花费。
防止双花攻击的一个中心化的解决方法是: 给每个发行的货币增加一个唯一标识码,再记录该货币在谁手上。每一次交易都需要央行确认。这个方法可以叫做记账法。
中心化记账法的问题是:任何交易都要通过央行确认合法性,但中心化系统会面临一些问题,可能有:
- 央行控制者滥发货币;
- 央行的数据库容易被攻击篡改;
- 交易确认造成的高负载;
- 单点故障;
如果要构建一个去中心化的货币系统,那么急需解决两个问题:
- 谁有权利发行货币?
- 如何验证交易的有效性: 也是如何防止双花?
比特币的每个交易都包含了输入、输出和「签名」。
- 输入部分包含了 币的来源和转账方的公钥哈希。
- 输出部分包含了 收款人的公钥哈希。
- 签名:私钥对交易的签名
一个转账的例子:
┌───────────┐ ┌──────────────┐ ┌─────────────┐
│ │ │ │ │ │
┌─────────────┼────┐ ┌┼────▼──────┐ ┌─┼─────▼──────┐ ┌─┼────────────┐
│ create coin │ │ │A┌──►B(5) │ │ B┌───►C(2) │ │ C────►E(7) │
│ ▼ │ │ │ │ │ │ │ │ │ │
│ ─────►A(10)│◄────┤ │ │◄────┤ │ │◄───┤ │ │
│ │ │ └──►C(5) │ │ └───►D(3) │ │ │ │
│ │ │ signed by A│ │ signed by B │ │ │signed by C │
└──────────────────┘ └─────▲──────┘ └──────────────┘ └─┼────────────┘
│ │
│ │
└──────────────────────────────────┘
输入部分说明币的来源很重要,因为它可以解决双花问题:如果在最后,B 又转给F账户(公钥的转换)5个coin,但实际上B已经在第二个交易中花费完了,再次转账就无法成功。
A 转给B的交易中,输入部分包含了A的公钥哈希,它被用来验证签名,但公钥哈希和交易的签名是可以伪造的,所以A的公钥哈希必须要与币的来源中的收款方的公钥哈希匹配。
这里产生了一个疑问,如果有人恶意的去匹配A的公钥哈希和签名,那不就可以匹配上了吗?
我的猜测:签名是无法伪造的,因为A是用私钥对整体交易进行了加密,也就是如果你想变动交易中的信息,签名就对不上;如果是全部复制一模一样的交易,但上面说到这种区块链设计又避免了双花攻击,所以全部复制也就没有了意义。
实际系统的扩展
实际系统中每个区块包含了很多交易,区块又分成了block header和block body,签名只是针对于block header,header中的merkle root hash指向block body,block body中的交易组织成了merkle tree,保证了交易不可篡改的特性。
┌───────┐◄───┬───────┐◄────┬───────┐
│header │ │header │ │header │
└───┬───┘ └───┬───┘ └───┬───┘
▼ ▼ ▼
┌───────┐ ┌───────┐ ┌───────┐
│ body │ │ body │ │ body │
│ │ │ │ │ │
│ │ │ │ │ │
└───────┘ └───────┘ └───────┘
区块具体包含:
- block header:
- version
- hash of previous block header
- merkle root hash: 保证了body中的交易是无法篡改的
- target: H(block header) <= target
- nonce
-
blocker body:存储了交易列表,这些交易又组织成了merkle tree。header中持有的merkle root hash保证了交易不可篡改的形状
- full node: full validating node
- light node: only including block header
交易是如何写入区块链中的
39分开始
这节的主要问题是:谁来决定哪些交易按照什么顺序被写入区块链中?
分布式共识
区块链是一个分布式的账本,账本的内容要取得分布式的共识。
distributed consensus
分布式共识的一个简单例子就是分布式哈希表。
分布式系统中有很多不可能结论(Impossibility result):
- FLP impossibility result:在一个异步(asynchronous)系统里,即使只有一个成员有问题(faulty),也不可能取得共识。
- CAP theorem:Consitency, Availability, Partition tolerance. 三者只能取其二。
按照DDIA中的说法,P是必然存在的,出现P时只能选择CP或者AP
- Paxos:能够保证Consitency,但是某些情况下有可能小概率的一直没有办法达成共识。
比特币共识
如何设计比特币的共识协议,来防止系统中存在恶意的节点攻击。
简单的设计思路:直接投票。
直接投票的问题有:
- 节点投票非法的候选区块
- 节点不投票:行政不作为
- 效率问题:网络延迟,每轮投票等多久
但更大的问题是:任何基于投票的方案都要确定谁有投票权(membership)。
联盟链中基于投票的方案是可行的,因为不存在恶意的节点。
直接投票在公链中的缺点是:由于比特币中账户的生成是可以无限的,恶意的节点可以产生无限的账户,当产生账户超过总数的一半,投票本身就是恶意攻击,这也被称为女巫攻击(Sybil attack)。
比特币中利用了一个很巧妙的机制来解决这个问题,基于计算力投票(工作量证明)而不是账户数目投票来防止女巫攻击。每个节点都可以在本地构造一个候选区块,把他认为合法的交易放到区块中,然后尝试各种nonce
值,只要满足H(block header) <= target
,就获得了记账权,也就是获得了向比特币区块链中中写入下一个区块的权利,其他节点收到这个区块之后验证区块内容的合法性。
Longest Valid Chain
另一个问题来了,通过合法性验证的区块就一定会被接受吗?
看下面这个例子:
┌──────┐◄──┬──────┐◄───┬──────┐◄───┬──────┐
│C->A │ │ │◄-┐ │ A->B │ │ │
└──────┘ └──────┘ │ └──────┘ └──────┘
│
└──┬──────┐
│A->A' │
└──────┘
A 转B 之后,A又转给它自己,相当于把A->B给回滚了。
内容合法的区块不一定在最长合法链上(Longest Valid Chain),这种也被称为forking attack。
比特币协议中规定:接受的区块应该是在最长合法链上。
临时性的分叉的非最长链被称为orphan block,会被丢弃掉。
┌───────┐◄──┬───────┐
┌───┤ │ │ │
┌──────┐◄──┬──────┐ ◄───┬──────┐◄───┬──────┐ │ └───────┘ └───────┘
│C->A │ │ │ ◄┐ │ A->B │ │ │◄┘
└──────┘ └──────┘ │ └──────┘ └──────┘◄┐ ┌───────┐
│ └───┼ │
│ └───────┘
└──┬──────┐ orphan block
│A->A' │
└──────┘
为什么节点要去争夺记账权呢?
获得记账权的节点可以获得铸币的奖励(block reward),coinbase transaction是比特币中发行新的比特币的唯一方法,coinbase transaction不用指定币的来源。
最开始每一个发布的区块可以产生50BTC,每过21万个区块(大概4年) 出块就需要减半。
视频1小时21分
课后问题:
- 比特币的共识机制要取得的共识是什么?只有获得记账权的节点才能写入区块。
- 如何防范女巫攻击?
- 每秒钟能够试多少个nonce的数目,称为hash rate,hash rate决定了出块的概率。
- 争夺记账权的过程:mining
- 争夺记账权的节点被称为矿工miner