{"content":{"title":"比特币原理","body":"# 公私钥对\r\n        使用比特币首先需要拥有自己的公私钥对，简单理解的话，公钥相当于你的账户，私钥相当于的你密码。在使用比特币交易之前，首先需要生成一个公私钥对，私钥是随机选取的在1-2^256数字之间的一个随机数，然后通过椭圆曲线算法可以从私钥计算得到公钥，这是不可逆转的过程：K = k * G。其中k是私钥，G是被称为生成点的常数点，而K是所得公钥。其反向运算，被称为“寻找离散对数”——已知公钥K来求出私钥k——是非常困难的，就像去试验所有可能的k值，即暴力搜索。\r\n        公钥和私钥的应用保证了“签名”的应用。当在比特币网络中进行转账时，通过“签名”可以明确是由哪个账户转出的，从而防止不良分子对其他账户比特币的盗取。在发布交易时，通过自己私钥签名，其他人可以根据公钥进行验证，从而保证该交易由自己发起。也就是说，只有拥有私钥，才能将该账户中的比特币转走。\r\n \r\n # 数据结构\r\n## SHA256函数\r\n         SHA256是一种密码散列函数，说白了它就是一个哈希函数。对于任意长度的消息，SHA256都会产生一个256bit长度的散列值，称为消息摘要，可以用一个长度为64的十六进制字符串表示，即 输入 x  就会得到一个哈希值H(x) = y。使用SHA函数是因为它有三个性质是比特币需要，1、防止哈希碰撞，就是输入的值不同的话，函数算出的值也是不同的，在哈希函数中，如果输入不同的值能得到同一个输出值，那么成为哈希碰撞，SHA256函数目前并没有发生哈希碰撞的情况，所以现在一致认为这个函数具有防止哈希碰撞的特点。2、单项不可逆运算，即已知 x 和 sha256函数可以算出  y 的值，但是已知y不能逆运算出x。3、计算结果不可预测，就是哈希值不能预测出回出现在某个区间内，如果想要得到一个哈希值处于某个区间范围内，没有什么好办法，只有一个一个输入x试过去。\r\n## Hash pointer（哈希指针）\r\n### 指针\r\n        在程序运行过程中，需要用到数据。最简单的是直接获取数据，但当数据本身较大，需要占用较大空间时，明显会造成一定麻烦。因此，可以引入指针这一概念。当需要获取数据时，只需要按照指针所给的地址，去对应的位置读取数据即可，这样大大节省了内存空间。在实际中，为了便于程序移植性等原因，指针实际上存储的是逻辑地址而非物理地址。\r\n### 哈希指针\r\n        区块链结构本身为一条链表，节点为区块。而传统链表实现，便是通过指针将各个节点串联起来而称为最终的链。使用哈希指针替换普通指针，当节点（区块）中内容发生改变，该哈希值也会发生改变，从而保证了区块内容不能被篡改。\r\n![image.png](https://img.learnblockchain.cn/attachments/2022/11/gd9ZBnF0637086f27c063.png)\r\n## Merkle Tree 默克尔树\r\n        Markle Tree是一颗二叉树，是比特币系统中又一个重要的数据结构。Markle Tree用哈希指针代替了普通指针。父节点存储是子节点的哈希值，叶子节点存储交易数据。该数据结构的优点在于：只需要记住Root Hash（根哈希值），便可以检测出对树中任何部位的修改。\r\n ![image.png](https://img.learnblockchain.cn/attachments/2022/11/wy0cf45Q63708a45ebe72.png)\r\n#### Markle Tree的实际用途\r\n        Markle Tree可以用于提供Markle Proof。关于Markle proof，需要先了解比特币系统中节点。比特币中节点分为轻节点和全节点。全节点保存整个区块的所有内容，而轻节点仅仅保存区块的块头信息。为什么要分轻节点和全节点？ 因为硬件的局限。一个区块大小为1MB，对于移动便携设备来说，如果存储区块的所有内容，则所需空间过大，而这是不现实的。所以轻节点只需要存储区块块头信息，全节点存储区块所有内容即可。\r\n        当需要向轻节点证明某条交易是否被写入区块链，便需要用到Markle proof。我们将交易到根节点这一条路径称为Markle proof，全节点将整个Markle proof发送给轻节点（如下图所示），轻节点即可根据其算出根哈希值，和自己保存的对比，从而验证该交易是否被写入区块链。只要沿着该路径，所有哈希值都正确，说明内容没有被修改过。\r\n![image.png](https://img.learnblockchain.cn/attachments/2022/11/LkhlfcIV63708e279fa33.png)\r\n\r\n## 区块结构\r\n      每一个区块是由块头block header和 块身block body组成。block header 主要存储一些宏观信息，block body 存储交易信息。\r\n![image.png](https://img.learnblockchain.cn/attachments/2022/11/WhRg1C2Z637098c8ae2b5.png)\r\n### block header\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2022/11/x5JjeHQG63709a301b208.png)\r\n\r\n\r\n# 比特币的共识协议\r\n        在比特币中当交易信息被转发到网络上面，由矿工记录下交易信息，打包成一个区块然后发布，相当于把交易记录写入区块链。那么这个发布区块的人该如何选取呢，谁拥有向区块链写入数据的权利呢，这就要涉及关于比特币的共识机制。\r\n## 数字货币中经常出现的问题\r\n### 双花攻击\r\n        数字货币本身为带有签名的数据文件，可以进行复制。即：对用户来说，可以将同一货币花费两次。\r\n    修改：对货币添加唯一编号（不可篡改），每次支付向货币发行单位查询真伪。该方法每次交易都需要依赖于第三方机构来判断货币真伪且防止双花攻击。是一个典型的第三方中心化方案。现实中，我们通过支付宝、微信、信用卡等各种支付方式交易时，必然会依赖于第三方机构。由于这些第三方机构具有较高的可信度，有政府进行背书，所以可以采用这种方案。\r\n        但是，很多场景下，并不存在这样一个可信赖的第三方机构。基于这个背景，以去中心化思想为核心的比特币系统便吸引了人们的注意力。\r\n### 去中心化需要解决的问题\r\n        数字货币的发行由谁执行？如何发行？发行多少？什么时候发行？在传统中心化货币体系中，这些问题我们可以交给第三方机构（如：央行）。当引入去中心化思想后，系统中节点平等，交易不通过第三方，那么货币发行权的分配必然是一个需要解决的问题。在比特币系统中由挖矿来决定货币发行权和发行量。\r\n        如何验证交易是否有效？如何防止双花攻击？同样，在传统中心化体系中，该问题的解决由第三方机构来完成。而剔除这一机构后，交易双方如何能够验证交易的有效性？如何防止系统中恶意用户作恶获取收益？这也是去中心化交易系统需要解决的问题。\r\n        该问题的解决，依赖于系统中维护的一个数据结构，记录货币的使用情况（是否被花过？被谁花过？）。该数据结构由系统中全体用户共同维护，保证了交易的有效性。该数据结构，便是区块链。\r\n## 共识协议\r\n### POW 工作量证明\r\n        背景：假设系统中存在部分节点有恶意，但存在比例较小。大多数节点为“好”的节点，在这种情况下进行共识协议设置。\r\n        想法1：直接投票\r\n        某个节点打包交易到区块，将其发给其他节点，其他节点检查该候选区块，检查若正确投赞成票，若票数过半数，加入区块链。\r\n        存在的问题1——恶意节点不断打包不合法区块，导致一直无法达成共识，时间全花费在投票上。\r\n        存在的问题2——无强迫投票手段，某些节点不投票（行政不作为）。\r\n        存在的问题3——网络延迟事先未知，投票需要等多久？效率上会产生问题。\r\n        更大的一个问题——membership。如果是联盟链，对加入成员有要求，可以基于投票。但比特币系统，任何人都可以加入，且创建账户及其简单，只需要本地产生公私钥对即可。只有转账（交易）时候,比特币系统才能知道该账户的存在。这样，黑客可以使用计算机专门生成大量公私钥对，当其产生大量公私钥对超过系统中一半数目，就可以获得支配地位（女巫攻击）。所以，这种简单的投票方案也是不可行的。\r\n        比特币系统中采用了很巧妙的方案解决这个问题。虽然仍然是投票，但并非简单的根据账户数目，而是依据计算力进行投票。\r\n        在比特币系统中，每个节点都可以自行组装一个候选区块，而后，尝试各种nonce值(nonce是区块中的一个可变的参数，可以自行改变值)，使得区块的块头信息的哈希取值小于系统给定的某一个范围区间，这就是挖矿[H(block header)<=target]\r\n        当某个节点找到符合要求的nonce，便获得了记账权，从而可以将区块发布到系统中。其他节点受到区块后，验证区块合法性，如果系统中绝大多数节点验证通过，则接收该区块为最新的区块并加入到区块链中。\r\n        这种共识机制称之为工作量证明（POW prove of work），通过不停尝试不同的nonce值计算出系统的给定的区块哈希值范围，从而获取记账权，从理论的角度，在相同情况下，尝试nonce次数多的节点获得记账权的概率更大。\r\n### 最长链原则\r\n        最长链原则指的是在比特币的区块链上只承认最长的那条链是合法链。\r\n        1.会不会合法区块被拒绝？\r\n        如果同时在两条长度相同的链，发生分叉的情况下，暂时保存分叉情况，但区块链只承认最长合法链，随着时间推移，必然存在某一条链变成最长合法链。这样，下面区块的信息就作废了，不管这个区块合法与否。\r\n        2.分叉攻击\r\n        如图所示，A用户对上面的A转账给B的记录回滚，从而非法获取利益。在两条链上，发现交易都合法。这是一个典型的双花攻击。A给B转账后，用分叉攻击将钱又转回来，覆盖掉原来的记录。\r\n        在比特币系统中，这种情况实际上很难发生。因为大多数矿工认可的是最长的合法链，会沿着上面的链继续挖下去。而A这个攻击者要想回退记录，就必须使得下面的链变得比上面的链还长。理论上来说，攻击者需要达到整个系统中51%的计算力，才能使得这种攻击成功。\r\n        此外，区块链正常运行场景下，也可能会发生分叉。当两个节点同时获得记账权时，会有两个等长的合法链。在缺省情况下，节点接收最先听到的区块，该节点会沿着该区块继续延续。但随着时间延续，必然有一个链胜出，由此保证了区块链的一致性。（被扔掉的区块称为“孤儿区块”）\r\n![image.png](https://img.learnblockchain.cn/attachments/2022/11/60IUqlQa6370a5cca8a74.png)\r\n\r\n### 比特币激励机制\r\n         为什么系统中节点要竞争记账权？需要提供算力和电力成本，节点为什么要去做？\r\n         比特币系统设计之初便考虑到了这个问题，那就是引入激励机制。比特币通过设置出块奖励来解决该问题，一个获得合法区块的节点，可以在区块中加入一个特殊交易（铸币交易）。事实上，这种方式也是唯一一个产生新比特币的途径。\r\n        比特币系统设计规定，起初每个区块可以获得50个比特币，但之后每隔21万个区块，奖励减半。\r\n        但是这样就可以了吗？？？\r\n        区块中保存交易记录，那么，会不会存在节点只想发布区块而不想打包交易？中本聪在设计该系统时，引入了交易费。在一个区块中，其输入>=输出，差值便是给区块所属节点的手续费。\r\n\r\n## 比特币系统中的具体实现\r\n### UTXO\r\n        区块链是一个去中心化的账本，比特币采用了基于交易的账本模式。然而，系统中并无显示记录账户包含比特币数，实际上其需要通过交易记录进行推算。在比特币系统中，全节点需要维护一个名为UTXO(Unspent Transaction Output尚未被花掉的交易输出)的数据结构。UTXO集合中每个元素要给出产生这个输出的交易的哈希值，以及其在交易中是第几个输出。通过这两个信息，便可以定位到UTXO中的输出。\r\n        为什么要维护这样一个数据结构？？？\r\n        为了防范“双花攻击”，判断一个交易是否合法，要查一下想要花掉的BTC是否在该集合中，只有在集合中才是合法的。如果想要花掉的BTC不在UTXO中，那么说明这个BTC要么根本不存在，要么已经被花过。所以，全节点需要在内存中维护一个UTXO，从而便于快速检测double spending（双花攻击）。\r\n### BTC挖矿难度调整\r\n        为什么要调整挖矿难度\r\n        挖矿本质上就是不断调整block header中的nonce值，使整个block header的哈希值小于等于给定的目标阈值。即：H(block header)<=target.（target便是目标阈值，target越小，目标难度就越大）对于挖矿难度的调整。比特币系统采用的哈希算法为SHA-256，所以整个输出空间大小为2^256，调整目标空间所占比例，简单的说需要目标值前需要多少个0。\r\n        如果不调整挖矿难度会怎么样？\r\n        系统总算力越来越强，若挖矿难度保持不变，则出块时间会越来越短。\r\n        出块时间越来越短是好事吗？\r\n        出块时间缩短，那么交易可以很快便被写入区块链，并且提高了系统响应时间，增加了区块链系统效率。但是，出块时间并不是越短越好。出块时间太短，也会造成一定的问题。首先，区块在网络上传播具有时延，假如出块时间为1秒，但网络传播需要10秒，则会使得系统中节点经常性处于不一致的状态，增加了系统不稳定性，且系统经常性位于分叉状态（不仅二分叉，乃至多分叉）。分叉过多，则不利于系统达成共识，且会造成算力分散，使得黑客攻击成本大大降低(不再需要整个系统51%的算力)。\r\n         10min的出块间隔是最优吗？\r\n         当然不是，但可以确定的是，系统出块时间需要维持在一个定值附近。当然，对于一个交易系统来说，10min这样一个交易时间是比较长的。但对于跨国交易来说，这个时间反而大大缩短了交易时间，减少了相应成本。\r\n         在BTC协议中规定，每隔2016个区块需要调整一次难度，根据10min产生一个新区块可以得到，大概需要14天的时间\r\n![image.png](https://img.learnblockchain.cn/attachments/2022/11/Zn22gNXe6370b8f488379.png)\r\n### 挖矿过程的概率分析\r\n        挖矿本质上是不断尝试各种nonce，来求解这样一个puzzle。每次尝试nonce，可以视为一次伯努利试验。最典型的伯努利试验就是投掷硬币，正面和反面朝上概率为p和1-p。在挖矿过程中，一次伯努利试验，成功的概率极小，失败的概率极大。挖矿便是多次进行伯努利试验，且每次随机。这些伯努利试验便构成了a sequence of independent Bernoulli trials(一系列独立的伯努利试验)。根据概率论相关知识知道，伯努利试验本身具有无记忆性。也就是说，无论之前做多少大量试验，对后续继续试验没有任何影响。\r\n        对于挖矿来说，便是多次伯努利试验尝试nonce，最终找到一个符合要求的nonce。在这种情况下，可以采用泊松分布进行近似，由此通过概率论可以推断出，系统出块时间服从指数分布。(需要注意的是，出块时间指的是整个系统出块时间，并非挖矿的个人)\r\n        系统平均出块时间为10min，该时间为系统本身设计，通过难度调整维护其平均出块时间。指数分布本身也具有无记忆性。也就是说，对整个系统而言，已经过去10min，仍然没有人挖到区块，那么平均仍然还需要等10min。也就是说，将来要挖多久和已经挖多久无关。\r\n### 全节点和轻节点\r\n![image.png](https://img.learnblockchain.cn/attachments/2022/11/vfiyO1DN6370ba2cab748.png)"},"author":{"user":"https://learnblockchain.cn/people/10154","address":null},"history":null,"timestamp":1668332424,"version":1}