BTC-实现
约 7163 字大约 24 分钟
2021-09-05
相关术语
transaction-based ledger 基于交易的账本模式
account-based ledger 基于帐号的账本模式
UTXO(Unspent Transaction Output) 未使用的交易输出
total inputs 交易总输入
total outputs 交易总输出
block reward 出块奖励
coinbase transaction 铸币交易
transaction fee 交易费
digital commitment 数字化承诺
Bernoulli trial 伯努利试验
Bernoulli process 伯努利过程
memoryless 无记忆性
Poisson process 泊松过程
exponential distribution 指数分布
probability density 概率密度
progress free 过去的无效,不算数
geometric series 几何序列
Bitcoin is secured by mining 比特币被挖矿所保护
membership 会员、成员
malicious 恶意的
double spending 双花攻击
forking attack 分叉攻击
irrevocable ledger 不可篡改账本
confirmation 确认
zero confirmation 零确认
selfish mining 自私挖矿
概述
比特币采用是基于交易的账本模式transaction-based ledger
。每个区块里记录的是交易信息,有转账交易,有铸币交易,但是系统当中没有显式的记录每个账户有多少钱。比如想要知道理解A账号上有多少钱,这个需要交易记录来推算,区块链上一共有多少向A账户上转账的交易,共有多少币,这些币当中有哪些已经花掉了,就是这样来推算A账户上有多少钱。
UTXO
比特币的全节点要维护一个UTXO
(Unspent Transaction Output) 的数据结构,即还有没被花掉的交易输出。比特币系统中一个交易可能有多个输出。理解比如A的一个交易,A向B转账5个BTC
,向C转账3个BTC
,如果B的5个BTC
被B花掉了,那么这个交易输出就不在UTXO
里面了。就是同一个交易,有的输出在UTXO里面,有的可能不在,可能被花掉了。UTXO
集合当中每个元素,要给出产生这个输出的交易的hash
值,以及它在这个交易里是第几个输出。这里个信息就可以定位到UTXO
中的输出。
为什么要维护一个UTXO
,就是为了检测double spending
。新发布的交易是否合法,是需要查一下UTXO
。想要花掉的币,只有在这个集合里面,才是合法的。如果不在这个集合里面,就说明,要么这个币是不存在的,要么是这个币以前已经被花掉了。所有全节点要在内存中维护UTXO这样一个数据结构,以便快速检测double spending
。
每个交易会消耗一些输出,同时也会产生新的输出。理解比如A把5个币转给B之后,B把这个5个币花出去给D了。这个时候,A到B的输出就不在UTXO
里面了,B到D的输出又保存到了UTXO
里面了。
如果某个人收到一些币之后始终都不花,那么这个信息,就要永久的保存的UTXO
里面。可能是不想花,也可能想花花不了,因为他把密钥丢失了。。。UTXO的数据也是逐渐增大,不过目前为止,装在一个服务器的内存里还是完全没有问题的。
每个交易的所有输入等于这个交易的所有输出,total inputs = total outputs
,这点很容易理解。但是有些交易,它的total inputs
略微大于total outputs
,比如输入是1BTC
,输出是0.99BTC
,这里面的差额0.01BTC
就作为交易费给获得记账权发布区块的那个节点。上一篇介绍过,为什么节点消耗算力来竞争记账权,是为了获得出块奖励block reward
,发布一个区块,可以有一个特殊的coinbase transaction
,获得一定数量的比特币作为报酬。但是光有这个出块奖励可能是不够的,发布区块的节点,为什么要把别的交易打包的区块里,这样做对他有什么好处呢?
transaction fees
比特币的交易费(Bitcoin transaction fees)是用户在比特币网络中发送交易时支付给矿工的一小笔比特币,用以激励矿工将交易包含在下一个区块中。以下是比特币交易费的简洁介绍:
- 费用目的:交易费是矿工验证和记录交易到区块链的激励,确保交易及时被处理。
- 费用计算:比特币交易费基于交易大小(字节)和每字节的费用率(聪/字节)计算得出。交易大小取决于交易的输入和输出数量。
- 网络拥堵:在网络拥堵时,交易需求超过区块容量,用户提高交易费用以优先处理自己的交易,类似于高峰时段的交通拥堵费。
- 费用波动:比特币交易费随市场供需动态变化,有时可能很低,有时则需要支付更多以确保交易被快速确认。
- 费用影响因素:交易费受区块空间限制、网络拥堵程度和交易复杂性影响。涉及多个输入和输出的交易通常需要更高的费用。
- 费用历史:比特币交易费在历史上有高有低,例如在2021年4月达到约60美元的高点。
- 2024年数据:截至2024年,比特币平均交易费约为3.291美元/交易,而在2024年1月14日,见证了最高费用日,每笔交易费用为10.28美元。
比特币交易费是比特币网络中一个重要的经济机制,它不仅激励矿工工作,还帮助防止网络中的垃圾交易。
coinbase transaction 回顾
Coinbase transaction(Coinbase交易)指的是在比特币区块链中,由矿工创建的一种特殊类型的交易。以下是Coinbase交易的简洁介绍:
- 区块奖励:Coinbase交易是每个新区块中的第一个交易,它不涉及输入,直接产生新比特币作为区块奖励给成功挖矿的矿工。
- 交易结构:Coinbase交易包含一个特殊的输入字段,通常包含一些矿工想要包含的信息,如矿工的地址或一条消息。
- 无前导交易:与普通交易不同,Coinbase交易没有前导交易输入,因此它产生的比特币是“新造”的。
- 激励机制:Coinbase交易是矿工挖矿的主要激励之一,除了交易费之外,矿工还可以获得区块奖励。
- 交易费收入:在Coinbase交易中,矿工还可以收集该区块内所有交易的交易费,作为额外收入。
- 每区块一次:每个新区块都包含一个Coinbase交易,因此矿工大约每10分钟(比特币网络的目标区块时间)可以获得一次奖励。
- 区块链历史:Coinbase交易是区块链历史上最早的交易之一,它们记录了比特币的发行和矿工的挖矿活动。
Coinbase交易是比特币网络中一个独特的组成部分,它不仅为矿工提供了经济激励,也是新比特币进入流通的主要方式。
交易费
比如某个自私的节点,他发布区块的时候,只打包了属于自己的交易记录,别的交易都不管。因为把别的交易都打包进去,对他来说并没有好处。而且还有一定的代价,因为要验证这些交易的合法性。而且区块里打包的交易多的话,占用的带宽也比较大,在网络上传播的速度也慢。所以只有出块奖励的话是不够的,比特币设置了第二个激励机制,就是交易费transaction fee
,可以理解成一种小费。你把我的交易打包的区块里,我给你点小费。目前交易费的金额都很小,向举例的0.01BTC的交易费已经是比较大的了,也有一些简单的交易是没有交易费的。因为出块奖励是逐渐减小的,每隔21w个区块,出块奖励就会减半,所以交易费也是有必要的激励机制。
21w个区块大概是多长时间呢?比特币设置的平均出块时间上10分钟,就是每隔10分钟会产生新的区块。算下来大概是4年。也就是每隔4年,出块奖励就会减半。很多年以后,这个出块奖励就会变得很小了,到那个时候,这个交易费可能就变成主要的奖励了。
60分钟∗24小时∗365天21万∗10分钟≈4年
除了比特币这种transaction-based ledger
模式,与之对应的还有account-based ledger
模式,像以太坊就是基于这种模式,在这种模式,系统是要显式的记录每个账户上有多少个币。这个跟平时日常体验就比较类似,就比如查询自己都银行余额。比特币这种隐私保护性比较好,当然也有一些代价,比如比特币中转账要说明币的来源,因为没有地方记录你有多少币的概念,就是没有账户这个概念就要付出的代价。
区块信息
接下来看一下区块链中具体的信息是怎么样的。
block header
nonce
最多也就2的32次方的选择,现在难度比较大,只用这个可能搜索空间不够大。所以可以调整一下nBits
来增强难度。
看一下介绍:
- version:版本,这个调整不了
- previous block header hash:前一个block header的hash
- merkle root hash:merkle tree的根hash
- time:产生区块的时间
- nBits:目标域值编码后的版本是4个字节,这个是按照协议的要求定期调整,不能更改
- nonce:随机数
既然光改nonce不够,只能调整merkle root hash了。但是merkle root hash能随便改么?
前面介绍过,每个发布区块的里面有一个特殊的铸币交易coinbase tx
,这是比特币系统中产生新的币的唯一方式。 这个交易没有输入,因为它是凭空造出来的。它有一个coinbase
域,可以写入任何的内容,在这里面写任何内容是没有人管的。之前介绍过的digital commitment
,数字化承诺,就可以把commitment
写到这个里面。
digital commitment 回顾
提前公布预测结果会影响股市,实现可以公布一个预测结果的hash值,这个hash值就可以写在coinbase这个域里面。
Coinbase tx
看一下Coinbase tx
的结构。其中有一个Coinbase
域,这个域有什么用呢?在这里写什么内容会对block header
有影响么?调整了coinbase
之后,会导致merkle root
的hash
发生变化。理解所以可以把这个coinbase
当作extra nonce
。块头里4个字节的nonce
不够用,这里还有很多字节可以用,比如把coinbase
的前8个字节当作extra nonce
来用,这样搜索空间一下就增到到了2的96次方。
coinbase
域的extra nonce
,算出block header
里的根hash之后,内层循环再调整header
里的nonce
。Normal tx
再看一个普通的交易,这个交易里面有俩个输入和俩个输出。左侧虽然写的是output
,其实是输入,是之前某次交易的输出作为本次的输入。右侧unspent
表示都还没花掉,会保存在UTXO
里面。已经下方表示的脚本,输入和输出都是用脚本来执行的。比特币系统中验证交易的合法性就是用input Script
和output script
配对后执行来完成的,但是理解要注意点是,不是把当前同一个交易中的这俩个脚本配对执行,而是把当前交易的输入脚本input script
和前面那个提供币的来源的output script
输出脚本配对。
挖矿
挖矿的过程就是不断的尝试各种nonce
来求解puzzle
,每次尝试nonce
可以看做是Bernoulli trial
(a random experiment with binary outcome
)。
Bernoulli trial
Bernoulli trial(伯努利试验)是概率论中的一个基本概念,它描述了一个简单的随机实验,具有以下特点:
- 二元结果:试验的结果只有两种可能,通常称为“成功”和“失败”。
- 独立性:每次试验都是相互独立的,即一次试验的结果不会影响其他试验的结果。
- 相同概率:每次试验成功的概率是相同的,这个概率用pp表示,失败的概率则是1−p1−p。
- 单次试验:关注的是单次试验的结果,而不是多次试验的总和。
伯努利试验的例子包括:
- 抛硬币:正面朝上为成功,反面朝上为失败。
- 射击目标:命中为成功,未命中为失败。
- 产品质量检测:通过为成功,未通过为失败。
伯努利试验是构建更复杂概率模型的基础,如二项分布就是由一系列独立的伯努利试验组成的。
比如每次掷硬币,每次掷硬币,俩种可能性,正面朝上或者反面朝上。这俩种可能性大概率可能不一样,比如正面朝上是P,反面是1-P。挖矿同样,每次尝试nonce
,成功的概率是微乎其微的,大概率是不行的。如果做很多的Bernoulli trial
,每个Bernoulli trial
都是随机的,那么这些Bernoulli trial
就构成了Bernoulli process
(a sequence of independent Bernoulli trial
)。
Bernoulli process
Bernoulli process(伯努利过程)是概率论和统计学中的一个概念,它是一系列独立的伯努利试验的集合。以下是伯努利过程的简洁介绍:
- 独立试验序列:伯努利过程由一系列独立的伯努利试验组成,每个试验只有两种可能的结果:成功或失败。
- 相同成功概率:在伯努利过程中,每个伯努利试验的成功概率都是相同的,用pp表示,失败的概率为1−p1−p。
- 随机变量序列:在伯努利过程中,每个试验的结果可以用一个随机变量表示,通常取值为1(成功)或0(失败)。
- 二项分布:在固定数量的伯努利试验中,成功的次数遵循二项分布。如果进行nn次独立的伯努利试验,成功次数XX的概率质量函数为: P(X=k)=(nk)pk(1−p)n−kP(X=k)=(kn)pk(1−p)n−k 其中,(nk)(kn)是组合数,表示从nn次试验中选择kk次成功的方式数。
- 应用广泛:伯努利过程在许多领域都有应用,包括金融风险管理、可靠性工程、机器学习中的分类问题等。
- 时间序列模型:在时间序列分析中,伯努利过程可以用来模拟一系列随机事件,如股票市场的涨跌。
伯努利过程是理解更复杂随机现象的基础,它提供了一个框架来分析和预测一系列独立随机事件的结果。
Bernoulli process
有一个性质,它是memoryless
,无记忆性。意思是,做大量的实验,前面的结果对后面是没有影响的,比如掷硬币,连续掷硬币都是反面朝上,那么下次正面朝上的概率就会大一些呢?不是的,仍然是P,跟过去的结果是无关的。挖矿也是,需要尝试大量的nonce
,才有可能找到符合要求的,这种情况,Bernoulli process
可以用Poisson process
近似。
Poisson process
Poisson process(泊松过程)是一种描述随机事件在连续时间或空间中发生次数的数学模型。以下是泊松过程的简洁介绍:
- 随机事件:泊松过程用于描述在固定的时间间隔或空间区域内,随机事件发生的次数。
- 独立增量:在泊松过程中,不同时间间隔内事件发生的次数是相互独立的。
- 平稳性:事件在任何长度为tt的时间间隔内发生的概率与时间间隔的起始点无关,只依赖于间隔的长度。
- 稀疏性:在非常小的时间间隔内,事件发生的概率非常小,几乎可以忽略不计。
- 参数λλ:泊松过程由一个参数λλ(称为强度或速率)描述,它表示单位时间内事件的平均发生次数。
- 概率分布:在给定的时间间隔内,事件发生的次数遵循泊松分布。如果XX表示在时间tt内事件发生的次数,那么XX的概率质量函数为: P(X=k)=(λt)ke−λtk!P(X=k)=k!(λt)ke−λt 其中,kk是非负整数,表示事件发生的次数。
- 应用广泛:泊松过程在许多领域都有应用,如电话呼叫到达、电子邮件接收、放射性粒子发射、交通事故发生等。
泊松过程是研究随机事件发生频率和时间间隔的重要工具,它提供了一个强大的框架来分析和预测在连续时间或空间中随机事件的发生。
实验的次数很多,每次成功的概率很小,这时候可以用Poisson process
来近似。
我们关心的是系统里产生区块的时间,系统里产生下一个区块的时间。这个在概率上可以推导出来,出块时间是服从指数分布的exponential distribution
,
Exponential distribution
Exponential distribution(指数分布)是一种连续概率分布,常用于描述独立随机事件发生的时间间隔。以下是指数分布的简洁介绍:
- 时间间隔:指数分布用于描述在泊松过程中,两个连续事件之间的时间间隔。
- 无记忆性:指数分布具有无记忆性(memoryless property),即未来事件发生的概率不依赖于已经过去的时间。
- 参数λλ:指数分布由一个参数λλ(称为速率参数)描述,它表示单位时间内事件的平均发生次数。
- 概率密度函数:指数分布的概率密度函数(PDF)为: f(x;λ)=λe−λxf(x;λ)=λe−λx 其中,x≥0x≥0表示时间间隔,λ>0λ>0是速率参数。
- 累积分布函数:指数分布的累积分布函数(CDF)为: F(x;λ)=1−e−λxF(x;λ)=1−e−λx 其中,x≥0x≥0。
- 期望和方差:指数分布的期望(均值)为1λλ1,方差为1λ2λ21。
- 应用广泛:指数分布常用于可靠性工程、排队论、生存分析等领域,如设备的寿命、顾客到达的间隔时间等。
指数分布是描述随机事件时间间隔的重要工具,它提供了一个强大的框架来分析和预测在连续时间中随机事件的发生。
这个是整个系统的出块时间,并不是某个矿工的出块时间。整个系统的平均出块时间是10分钟。这是比特币系统设计的,通过定期调整挖矿难度,使得平均的出块时间维持在10分钟左右。具体到矿工,取决于这个矿工的算力占系统算力的百分比。比如说A矿工的算力占系统总算力的百分之一,那么平均下来,系统里每产生100个区块,A能挖矿挖到一个区块,那么A平均就需要等1000分钟才能挖到一个区块。另外,这个probability density
也是memoryless
无记忆性的,这个函数曲线不管从任何位置阶段,仍然都是满足指数分布的。比如说,已经过去10分钟了,还没有人找到合法区块,那么接下来还要等多久,仍然是这个概率密度分布,平均还是要等10分钟。这个可能不符合直觉,因为平均是10分钟,已经挖了10分钟,还没有挖到,感觉应该快了。不是这样的,将来还要多少时间,跟过去已经挖了多少时间是没有关系的,仍然是平均10分钟。这种性质管它叫progress free
,意思是过去的progress
是不管用的、不算数的。
如果设计一个非progress free
的加密货币会怎么样呢,之前算的多,就更容易算出结果。会产生算力强的矿工会有不成比例的优势。是不公平的。所以progress free
恰恰是挖矿公平的保证。
总量
出块奖励是系统中产生新的币的唯一途径。而出块奖励是每隔四年减半的。这样产生的比特币数量就构成了集合序列geometric series
。
21万∗50+21万∗25+21万∗12.5+...
=21万∗50∗(1+1/2+1/4+...)
=21万∗50∗2
=2100万
无穷等比数列求和
包括过去发的比特币,和以后将要发的总量,一共就这么多,2100万个。
理解有些错误的理解,以为比特币挖矿的过程是解决某个数学难题。其实不是这样的,比特币求解的这个puzzle
除了比拼算力之外没有任何的实际意义。越来越难被挖到是因为出块奖励被认为的减少了。Bitcoin is secured by mining
。对于一个去中心化的,没有membership
控制的系统来说,挖矿提供了一种形借算力投票的有效手段。只要大部分算力掌握在诚实节点手里,系统的安全性就能够得到保证。所以挖矿这个过程从表面来看,没有什么实际意义,但是这个机制对于维护系统的安全性是非常有效的。
那么出块奖励每隔4年减半,那么挖矿的动力会越来越小么。从过去的几年来看,是恰恰相反的。即便趋于0,还有交易费。
安全性
假设大部分算力掌握在诚实节点手里,能不能保证写入区块链的交易都是合法的?
理解挖矿只是给出概率上的保证,毕竟大的概率保证。但是不能保证记账权不会落到有恶意的节点手里。比如90%是诚实节点,10%是有恶意节点。那么10%的情况下,记账权会落到有恶意Malicious
的节点。这时候会产生什么情况?假设一
它能不能偷币,把别人账上的钱转给自己?不能,因为没法伪造别人的签名。即便硬要写假的交易,也会因为交易含有非法的,不被接收,其他节点继续沿着上一个区块继续挖。
这对与攻击者来说,付出的代价是很大的,也得不到区块奖励了。等于没有偷到钱,白白损失了区块奖励。
假设二
它能不能把已经花掉的币,再花一遍,就是double spending
,肯定是不行的,
只能插入另一个分支上,形成forking attack
。
确认
需要注意的是,产生的区块插入什么位置,是要在刚开始挖矿的时候就决定的。因为设置的block header
里要填上前一个block header
的hash
。而不是获得记账权以后再说插入到什么位置。那么forking attack
的目的是什么呢。相当于回滚,不当获利。比如说网上购物,网站接收比特币支付。M发起交易把币转给网站。这个网站监听到这个交易写到区块链里面了,以为支付成功了。M拿到商品以后,又发起一个交易,把钱转给自己。然后把下面扩展成最长合法链,这样上面的区块就作废了。这样攻击的目的是既得到了商品,又把花出去的钱收回来了。
怎么防范这种攻击呢?如果这个转账交易不是最后一个区块,而是后面跟了几个区块,这种情况forking attack
的攻击难度就会大大增加,成功的可能性很小。一种简单的防范方法就是多等几个区块,或者说多等几个确认confirmation
。比特币系统默认是6个确认后,即为不可更改的。平均出块时间上10分钟,这个大概要等1个小时,还是挺漫长的。
有种说法是,区块链是不可篡改的账本irrevocable ledger
,所以这种不可篡改性只是一种概率上的保证。刚刚写入区块链的内容相对来说还是比较容易被篡改的。经过多个确认后,被篡改的概率就会大幅度下降。
其实还有一种确认,叫zero confirmation
,就是图中虚线部分,意思是这个交易记录发布出去了,但是还没有被写入到区块链中,就是交易记录发布出去了,但是下一个区块还有挖出来。还是购物的例子,就是购物网站监听或者委托第三方监听到了这交易记录,就发货了,就是zero confirmation
。虽然看似不安全,但是还是比较常见的。为什么呢,有俩个原因。因为M->A是率先发布的,会有比较大的概率不会接收下面的forking attack
的。第二个原因是,购物网站收款到发货天然有一定时间间隔的,比如说次日达。。中间可以取消发货的,当然这是比特币系统外的手段。
回到刚才的场景,记账权落到有恶意Malicious
的节点。还会产生什么情况?能不能故意不把某些合法的交易写到区块链?这是可以的。比特币协议并没有规定获得记账权的节点一定要把哪些交易发布到区块链。但是出现这种情况,问题也不大。因为这些合法的交易反正可以写到下一个区块。总有诚实的节点原因发布这些交易。其实区块链在正常工作情况下,也会出现合法的交易没有被包含的情况,可能就是这段时间,交易的数目太多了。比特币协议规定每个区块大小是有限制的,最多1M。所以可能产生这种情况,可能就要包含到下一个区块里面了。
如果,有恶意的连续挖了7个,超过6个确认但是先不发布,等到6个确认后,在全部发布。这种攻击方法有个名字称呼为selfish mining
,其实也是forking attack
的一种。正常情况下,肯定是挖到一个区块就发布一个,你不发布,别人发布,别人就得到了区块奖励了,你的区块就相当于作废了。 其实selfish mining
成功的概率并不大,以为你连续多次获得记账权本身概率就不大。
那么selfish mining
还有什么目的?最多就是减小竞争,就是提前算下一个区块的竞争压力小了那么一点点,因为本身就是Bernoulli process
,但是风险很大,不一定成功。回报也不是很高。