简介
本文的绝大部分内容都来自北京大学肖臻老师《区块链技术与应用》课程,其他参考资料也都罗列在文末的附录中。文章架构基本与老师的课程节奏一致,但也有部分调整,同时也加入了不少自己的理解和最新的技术进展,如有任何问题请直接联系我,希望这些笔记能对你的区块链学习之路有一些帮助。
密码学基础
Hash函数
哈希函数(Hash Functions)是密码学中的一种数学函数,它将任意长度的输入(通常被称为“消息”或“数据”)转换为固定长度的输出,这个输出通常被称为“哈希值”或“哈希码”。哈希函数的主要特点包括:
- 确定性:相同的输入总是产生相同的输出,这意味着无论何时对相同的数据应用哈希函数,都会得到相同的哈希值。
- 单向性:从哈希值几乎不可能反推出原始输入,这使得哈希函数在保护数据安全方面非常有用。
- 雪崩效应:即使输入数据发生微小的变化,也会导致哈希值发生显著变化,这有助于防止哈希碰撞。
- 抗碰撞性:很难找到两个不同的输入,它们产生相同的哈希值。在理想情况下,哈希函数应该能够抵抗预谋的碰撞攻击。
- Puzzle friendly: 无法事先预测出哪样的输入可以得出特定的哈希值,只能一个个试
在加密世界中的应用
应用1:
我们先来看个例子:hello
的 md5 哈希的结果是:5d41402abc4b2a76b9719d911017c592
而稍作修改的 hollo
的结果则是 181d1f65fc3edfc75945b24f22cd7e22
可以看出这两个的哈希结果完全不同
那么放在加密世界中,我们只需要对一段信息取一个哈希,然后保存这个哈希结果到区块链中就可以了。因为一旦有人篡改这些信息,那么对应的哈希也会发生巨大变化。
应用2:
我们都知道比特币是需要通过挖矿获得的,而挖矿的过程其实就是一个不断哈希的过程
比特币会实现放出一个 target space
,这里就比如是 000000
,当然实际情况会复杂的多
比特币的机制要求矿工们需要找到一个输入,使得这个输入在经过哈希计算之后哈希值,是以 000000
开头
如果矿工们找到了这样一个输入,就证明它已经尝试过工作了很久了,那么就发放一定的比特币作为奖励
签名
比特币使用公钥和私钥构建了一个非对称加密系统。
公钥和私钥
- 公钥:公开的,可以被任何人查看和使用。它类似于银行账户号码,别人可以通过你的公钥给你转账。
- 私钥:私密的,只能由拥有者知道。它类似于你的银行账户密码,能够证明你对某个公钥的控制权,并允许你签署交易。
签名过程
- 生成消息的哈希值:首先,将要签名的消息(msg)进行哈希运算,生成一个固定长度的哈希值。比特币使用SHA-256算法进行哈希运算。
- 哈希函数是一个单向函数,将输入转换为固定长度的字符串,且不同输入生成相同输出的概率极低。
- 对哈希值进行签名:使用私钥对生成的哈希值进行签名。签名过程生成一个数字签名,这个签名是特定于该消息和私钥的。
- 数字签名是通过椭圆曲线数字签名算法(ECDSA)生成的。这个签名确保了只有持有该私钥的人才能生成这个签名。
- 附加签名到消息:将生成的数字签名附加到原始消息上,形成一个完整的签名消息。
验证过程
- 获取公钥和签名:接收者会从签名消息中提取出公钥、签名和原始消息。
- 对消息进行哈希运算:与签名过程类似,接收者也会对收到的消息进行哈希运算,生成哈希值。
- 验证签名:使用发送者的公钥和生成的哈希值来验证数字签名的有效性。
- 如果验证成功,表示签名是由拥有该公钥对应私钥的人生成的,且消息在传输过程中未被篡改。
示例
假设你要向某人发送比特币交易:
- 你用你的私钥对交易信息(包括接收者地址、转账金额等)生成的哈希值进行签名,生成数字签名。
- 将这个数字签名附加到交易信息上,并将包含签名的交易信息广播到比特币网络。
- 比特币网络中的节点使用你的公钥对签名进行验证,确保该交易确实是由你发起的,且信息未被篡改。
数据结构
哈希指针
在区块链中,哈希指针代替了传统的数据结构中的普通指针,提供了一种更安全、更高效的数据存储和验证方式。
哈希指针不仅指向前一个区块,还包含前一个区块的哈希值。具体来说,当创建一个新块时,会对该块的内容(只计算区块头,不算区块体,也就是具体的交易信息)进行哈希运算,生成一个唯一的哈希值。这个哈希值既表示该块的内容,也指向前一个块。
Tamper-Evident Log
哈希指针的一个主要优点是它提供了一种不可篡改的日志(tamper-evident log)。具体机制如下:
- 完整性验证:由于每个区块都包含前一个区块的哈希值,任何对某个区块的篡改都会改变该区块的哈希值,从而导致其后所有区块的哈希值发生变化。这样,篡改行为可以很容易地被检测到。
- 防篡改链:因为每个区块都依赖前一个区块的哈希值,如果某人试图修改一个区块,不仅需要修改该区块,还需要修改其后的所有区块,这几乎是不可能完成的任务。
数据存储优化
由于哈希指针的这种链式结构,我们不需要保存整个区块链的数据,只需要保存最后几个区块就可以了。具体流程如下:
-
最后几个区块:只需要保存最后几个区块,因为每个区块都包含前一个区块的哈希值,可以通过这些哈希值验证整个区块链的完整性。
-
按需查找:如果需要访问更早的数据,可以通过这些哈希指针找到并验证数据的完整性。
区块链的模拟过程
https://andersbrownworth.com/blockchain/blockchain
Merkle Tree
在比特币系统中,Merkle Tree(默克尔树)是用于组织和验证交易数据的一种重要结构。它的基本单元是底层的数据块,这些数据块实际上是一笔笔交易。
每个block有一个默克尔树,树中每个叶子节点是一个交易的hash值(比特币使用双重SHA256哈希)。叶子节点的数量一定是偶数,然后并非每个block都恰好有偶数个交易。当block有奇数个交易时,最后一个交易会被复制一次(复制仅仅发生在默克尔树中而不是block中!)。
默克尔树自下而上的进行组织,叶子节点成对分组后将两个hash值组合后生成新的hash值,形成上层的树节点,重复整个过程直到只有一个树节点为止,也就是所说的根节点。根节点的hash值是整个交易集的唯一标识,保存在block头信息中,用于PoW过程。根节点(Root Hash)代表了整个树的哈希值,只要记住这个根哈希值,就可以检测到整个树上的任意修改。
Merkle Proof
Merkle Tree 的一个重要好处是可以进行 Merkle Proof。Merkle Proof 是一种用于证明某个数据块(交易)存在于一棵给定的 Merkle Tree 中的方法。
全节点与轻节点
- 全节点:保存了整个区块链的所有数据,包括所有的交易和块。
- 轻节点:仅保存区块头(Block Header),而不保存所有交易数据。
轻节点的交易验证
假设你在手机上运行的是一个轻节点,如果我给你做了一笔转账,你需要验证这笔交易已经存在于区块链中,这时就需要用到 Merkle Proof。
验证过程
- 接收路径(Merkle Proof):轻节点从全节点或其他来源接收一个路径,这个路径包括从目标交易到根哈希的所有哈希值。
- 验证路径:轻节点使用这个路径验证该分支路径的哈希值与最终的区块头(Block Header)是否一致。如果一致,就证明该交易存在于区块链中。
这个过程证明的是Proof of Membership,其复杂度是 O(logn)。
Proof of Non-Membership
如何证明某个交易不在区块链中(Proof of Non-Membership), 当前没有比较高效的方法,只能一个个查验,其复杂度是 O(n)。
Sorted Merkle Tree
如果交易数据是有序的,根据哈希值排序,这种结构被称为 Sorted Merkle Tree。这种结构允许快速查找某个交易是否存在。但比特币并没有用这种结构,它不需要这个功能,排序也是需要额外代价的。
BTC协议
比特币协议包括铸币、交易过程和防止双花攻击等机制。
铸币和交易过程
每笔交易包含输入和输出部分:
- 输入部分:说明币的来源(即之前的交易)和转账人的公钥。转账人的公钥需要与币来源的公钥相匹配,确保合法性。
- 输出部分:指明收款人的公钥。这次交易需要有发送人的签名,确保交易是由合法的持币人发起的。
哈希指针用于指向之前的某个交易,证明这部分钱的来源,防止凭空捏造币。这个机制也防范了双花攻击。
双花攻击
双花攻击是指同一笔比特币被花费两次的情况。比特币通过以下机制防止双花攻击:
- 区块链共识:每笔交易都需要被矿工打包进区块,并通过共识机制确认。
- 交易验证:当一个新的区块被广播时,网络中的所有节点都会验证其中的每笔交易是否合法,检查是否有双花行为。
- 最长链规则:比特币网络会选择最长的合法链。如果双花交易发生在不同的区块中,只有包含在最长链中的交易会被认可。
双花攻击检测示例
假设Alice试图将同一笔比特币分别转给Bob和Charlie:
- 广播两笔交易:Alice向Bob和Charlie分别发起两笔相同输入的交易,并几乎同时广播到网络中。
- 矿工打包:矿工收到这两笔交易,并分别打包进不同的区块中,形成两个分叉。
- 分叉传播:网络中的节点会接收到这两个分叉的区块链,暂时分裂为两个分支。
- 最长链选择:随着时间推移,矿工继续挖矿并生成新区块。当某个分支被延长,形成新的最长链时,另一个分支的区块将被丢弃,成为孤块。
- 交易确认:最终,只有包含在最长链中的交易会被确认和接受。此时,Alice的双花攻击会失败,因为只有一笔交易会被区块链网络接受,另一笔交易会被回滚。
比特币挖矿每十分钟一个区块,其实也是为了防止分叉攻击,不然时间太短,叉太多,就容易被攻击
分布式共识
谈到共识,我们可能会想到投票,但是任何基于投票的共识协议都有一个投票权的问题,可能会存在女巫攻击,在比特币系统中简单的采用投票来确定共识是不行的。比特币网络通过**工作量证明(Proof of Work, PoW)**来实现分布式共识,确保所有节点就区块链的状态达成一致。其核心思想是通过消耗计算资源来防止女巫攻击和其他恶意行为。具体过程如下:
- 挖矿过程:矿工竞争性地进行大量的哈希运算,试图找到一个满足特定条件的哈希值(即目标值以下的哈希)。
- 哈希值计算:矿工对区块头进行哈希运算,区块头包括前一个区块的哈希值、当前区块中的交易Merkle根、时间戳、难度目标(nbits)和随机数(nonce)。
- 目标值:难度目标(nbits)决定了哈希值必须小于的目标值。随着网络计算能力的变化,难度调整每2016个区块(大约两周)进行一次。确保新区块生成时间约为每10分钟一次。如果区块生成过快,难度会增加;如果生成过慢,难度会降低。
区块结构
每个区块由区块头(Block Header)和区块体(Block Body)组成。
区块头包含以下字段:
- 版本号(version):表明区块的版本。
- 前一个区块的哈希值(previous block hash):指向前一个区块,确保链条的连续性。
- Merkle根(Merkle root):当前区块中所有交易的哈希值经过Merkle树计算得到的根哈希。
- 时间戳(timestamp):记录区块创建的时间。
- 难度目标(nbits):当前区块的挖矿难度。
- 随机数(nonce):用于挖矿的计数器。
区块体包含一个交易列表(transaction list),记录所有包含在该区块中的交易。
区块验证
其他节点收到新区块后,会进行一系列验证,以确保区块的合法性:
- 哈希值验证:检查区块头的哈希值是否小于难度目标。
- 前一个区块的哈希:验证前一个区块的哈希值是否与本地链的最后一个区块匹配。
- **交易验证:**验证区块中的每笔交易是否合法,包括:
- 签名有效性:检查交易的签名是否由合法的私钥生成。
- 双花检测:确保每笔输入没有在之前的区块中被花费。
- Merkle根验证:检查交易列表的Merkle根是否与区块头中的Merkle根一致。
如果区块通过所有验证,它将被添加到本地区块链中,否则将被拒绝。
出块奖励
矿工在成功找到满足条件的哈希值后,获得记账权并将新区块广播到全网。新区块包含一个特殊的交易(铸币交易 coinbase transaction),用于奖励矿工:
- 出块奖励:最初的出块奖励为50 BTC,每经过210,000个区块(约4年)奖励减半。当前(2024年)奖励为6.25 BTC。
- 交易费用:除了出块奖励,矿工还可以获得包含在区块内交易的交易费用。这些费用由交易发起人支付,作为矿工打包交易的激励。
共识协议和分叉处理
最长链规则
比特币网络采用最长链规则来决定哪条链是合法的。即所有节点选择包含最多工作量(即最长)的合法链。这样确保了网络的一致性和防止分叉攻击(forking attack)。
分叉处理
如果两个矿工几乎同时找到有效区块,会出现链的分叉。此时:
- 暂时分叉:网络中的节点会临时分裂为两个分支,分别接收其中一个区块。
- 最终选择:当一个分支被后续区块延长并超过另一个分支时,较短分支上的区块将被丢弃,成为孤块(orphan block)。
- 回滚交易:孤块上的交易会被回滚到未确认状态,并可能被包含在后续的区块中。
BTC实现
比特币采用交易账本 (transaction-based ledger) 的方式记录每一笔交易,而不是直接维护每个钱包的余额。也就是说查询某个钱包的余额需要通过遍历所有交易记录来推算。
UTXO
UTXO(Unspent Transaction Output)代表未花费的交易输出,是比特币交易系统中的核心概念。
- 定义:每个UTXO包含了产生这个交易的哈希值(交易ID)以及它在交易中是第几个输出。
- 作用:用于防止双花攻击。一个比特币只能被花费一次,只有在UTXO集合中的币才是合法的。全节点需要在内存中维护这个集合。
- 交易过程:
- 消耗UTXO:每笔交易消耗一些UTXO作为输入。
- 产生新的UTXO:每笔交易也会产生新的UTXO作为输出
确认机制
确认交易是为了防止分叉攻击和确保交易的不可篡改性。一般来说,等待6个确认(即6个后续区块)被认为是足够安全的。
- 确认时间:平均每个区块的产生时间为10分钟,因此6个确认大约需要1小时。
- 零确认交易(Zero-confirmation):有些交易在未被打包进区块前就被接收,但这存在较高风险,因为交易尚未被确认。
区块大小
每个区块的大小限制为1MB,这限制了每个区块中能包含的交易数量。
- 打包交易:如果某些交易未能打包进当前区块,则需要等待下一个区块。
- 拥堵情况:当交易量大时,未确认交易会积压,需要支付更高的交易费以提高被打包的优先级。
BTC网络
比特币网络是一个去中心化的点对点(P2P)网络,每个节点在网络中都是对等的。
- 对等节点:比特币网络由多个对等节点(peer nodes)组成,每个节点都具有相同的地位,没有中央服务器或控制节点。
- 节点通信:节点之间通过TCP协议进行通信,交换交易信息和区块数据。
加入网络
新节点要加入比特币网络,需要连接到一个已知的种子节点(Seed Nodes)。这些种子节点帮助新节点发现并连接到其他节点。新节点通过种子节点获取其他节点的列表,然后尝试与这些节点建立连接。
节点连接和维护
- 邻居节点:节点会随机选择其他节点作为其邻居节点进行连接。这种选择没有就近原则,一个美国的节点可能会选择一个阿根廷的节点作为邻居节点,因此跨地域转账和线下面对面转账的时间差不多。
- 节点维护:节点会定期发送“ping”消息来检查邻居节点的存活状态。如果长时间没有收到某个节点的消息,该节点会被认为已退出网络,并将其从连接列表中移除。
交易传播和区块广播
- 交易池:每个节点维护一个交易池(Mempool),存储所有待确认的交易。这些交易等待被矿工打包进区块。
- 交易传播:当节点接收到新的交易时,会先验证交易的合法性,然后将交易广播给其邻居节点。邻居节点再进行同样的操作,确保交易在网络中传播开来。
- 区块广播:当矿工找到一个新的区块时,会将区块广播到网络中。节点接收到区块后,验证区块的合法性,并将其添加到本地区块链中。
网络拓扑和消息传递
- 简单鲁棒的设计:比特币网络的设计注重简单性和鲁棒性,而不是高效性。这种设计确保了网络的稳定性和安全性。
- 消息传递:节点之间通过一系列预定义的消息类型进行通信,例如
inv
(通告新交易或区块)、getdata
(请求数据)、block
(传输区块)、tx
(传输交易)等。 - 退出机制:如果节点长时间没有发送消息,将被视为已退出网络,其他节点会移除其连接。
BTC挖矿
挖矿难度
比特币挖矿难度是一个度量单位,用来表示找到一个有效区块的难易程度。难度与目标值(Target)密切相关,目标值(Target)是一个256位的数,表示哈希值必须小于这个值才能被接受。目标值的计算基于难度,难度越高,目标值越小,挖矿越难。
比特币的挖矿难度动态调整是为了让出块时间平均维持在10分钟左右。如果不调整挖矿难度,随着矿工算力的不断增加,出块时间会越来越短。这会导致临时分叉成为常态,分散系统的算力,不利于比特币系统的整体安全性。
动态调整的必要性
- 分叉问题:如果出块时间过短,矿工频繁找到新块,临时分叉现象会增加。频繁的分叉会导致系统算力分散,降低网络的整体安全性。
- 安全隐患:算力分散使得恶意节点更容易成功挖掘某条恶意分叉链,威胁网络的安全性。因此,保持稳定的出块时间有助于减少分叉,提高网络安全。
Nonce和Extra Nonce
- nonce:块头(Block Header)中包含一个4字节(32位)的nonce字段,矿工通过不断改变nonce值来尝试找到一个满足难度要求的哈希值。
- extra nonce:随着难度增加,单一的nonce可能不够用。矿工可以在coinbase交易中增加一个额外的字段(extra nonce)来扩展搜索空间。这个字段在coinbase交易中的位置允许矿工改变更多的数值,从而增加可调节的范围。
挖矿难度调整机制
比特币网络采用难度调整算法来确保出块时间的稳定性。具体机制如下:
- 难度调整周期:比特币网络每2016个区块(约两周)调整一次挖矿难度。
- 理想耗时:理想情况下,2016个区块所需的时间为20160分钟(2016个区块 × 10分钟/区块)。
- 调整公式:难度调整的公式为:
调整范围:每次调整的难度变化范围被限制在原难度的四分之一到四倍之间,避免因短期算力波动导致难度变化过大。
挖矿设备
挖矿设备的演变
- CPU(中央处理器):
- 初期阶段:比特币刚开始时,用户可以使用普通计算机的CPU进行挖矿。
- 特点:处理速度较慢,算力低,但对于早期的低难度挖矿足够。
- 缺点:能效比低,难以应对难度增加后的挖矿需求。
- GPU(图形处理单元):
- 中期阶段:随着挖矿难度的增加,矿工转向使用GPU进行挖矿。
- 特点:GPU具有大量并行处理单元,能够同时进行多次哈希计算,比CPU高效得多。
- 优势:算力大幅提高,适合挖矿需要高计算能力的工作。
- 缺点:功耗较高,设备成本上升。
- FPGA(现场可编程门阵列):
- 过渡阶段:在GPU之后,部分矿工开始使用FPGA。
- 特点:可以编程的硬件,能够针对特定算法进行优化。
- 优势:能效比高于GPU,灵活性较强。
- 缺点:开发难度大,需要专业知识。
- ASIC(专用集成电路):
- 当前阶段:目前,比特币挖矿主要使用ASIC矿机。
- 特点:专门为比特币挖矿设计的硬件,能够最大化哈希计算效率。
- 优势:能效比最高,算力极高,专为SHA-256算法优化。
- 缺点:成本高,缺乏灵活性,只能用于特定算法的挖矿。
挖矿设备的主要参数
- 算力(Hash Rate):
- 表示设备每秒钟可以进行的哈希计算次数,单位通常为TH/s(太哈希每秒)或GH/s(吉哈希每秒)。
- 算力越高,设备找到满足难度目标的哈希值的概率越大。
- 能效比(Efficiency):
- 表示每消耗一瓦电能产生的哈希计算能力,单位通常为J/TH(焦耳每太哈希)。
- 能效比越高,设备的电力消耗越低,挖矿成本越低。
- 功耗(Power Consumption):
- 表示设备在运行时的电力消耗,单位通常为瓦特(W)。
- 功耗越低,设备运行成本越低。
矿池
矿池的工作原理
比特币挖矿是一个竞争激烈的过程,单个矿工成功找到新区块的概率很低。为了增加收益的稳定性,矿工们可以加入矿池,通过共享算力来共同挖矿,按比例分配奖励。在比特币矿池中,提交分享(Share)是矿工向矿池证明其工作量和贡献的一种机制。分享的提交和验证过程是矿池运作的核心。
Share:是一个满足矿池设定的低难度目标的哈希值。虽然这些分享本身不足以找到一个新的区块(因为它们不满足全网的难度目标),但它们证明了矿工的工作量和算力贡献。
-
工作机制
- 任务分配:
- 矿池服务器将挖矿任务分配给矿工,任务包括一个特定的区块头模板和一个较低的目标难度。
- 矿工接受任务后,使用自己的设备尝试找到符合低难度目标的哈希值。
- 计算和提交:
- 矿工进行哈希计算,尝试找到一个哈希值,使其小于矿池设定的低难度目标。
- 一旦矿工找到一个满足低难度目标的哈希值,即生成了一个分享(Share),矿工将这个分享提交给矿池服务器。
- 矿工不断重复这个过程,提交多个分享,直到任务结束或被新的任务替换。
- 分享验证:
- 矿池服务器接收到矿工提交的分享后,会验证其有效性。
- 验证过程包括检查哈希值是否满足低难度目标,并确保分享是基于矿池分配的任务生成的。
- 任务分配:
-
奖励分配
- 矿池根据矿工提交的分享数量分配挖矿奖励。常见的奖励分配方式包括:
- PPS(Pay Per Share):按每个有效分享支付固定金额。矿工的收益与提交的分享数量直接相关,矿池承担找到区块的风险。
- PPLNS(Pay Per Last N Shares):奖励分配基于最近N个分享的比例,强调长期贡献。
- 矿池根据矿工提交的分享数量分配挖矿奖励。常见的奖励分配方式包括:
矿主如何防止矿工私藏区块
- 提交实时验证:矿池要求矿工提交所有找到的低难度哈希值(分享),并实时验证其有效性,确保矿工没有私藏行为。
- 监控算力波动:矿池监控每个矿工的算力波动,如果某矿工的算力突然大幅下降,矿池会怀疑其可能在私藏区块。
- 信誉评分:矿池为每个矿工建立信誉评分系统,长期表现良好的矿工会获得更高的奖励,而有不良记录的矿工则会被警告或踢出矿池。
矿池对去中心化的影响
矿池通过集中了大量矿工的算力,使得比特币挖矿变得更集中化,这对比特币的去中心化特性构成了一定威胁:
- 算力集中:大型矿池控制了网络中大量的算力,使得比特币网络的去中心化程度降低。
- 共识影响:算力集中在少数矿池手中,使得这些矿池在共识过程中具有更大的影响力,甚至可能左右比特币网络的决策。
51%攻击的风险
如果某个矿池或联合矿池控制了比特币网络超过51%的算力,就可能发起以下攻击:
- 双花攻击(Double Spending Attack):攻击者可以创建两笔使用相同UTXO的交易,并选择在私链上确认其中一笔交易,而另一笔交易则在公开链上确认。通过51%算力优势,攻击者可以让私链超越公开链,使得公开链上的交易失效。
- 分叉攻击(Fork Attack):攻击者可以在网络上制造分叉,通过控制较长链条来使得较短链条上的交易失效,导致交易回滚。
- 拒绝服务攻击(Boycott Attack):攻击者可以选择不将某些交易或区块广播到网络中,导致这些交易或区块无法被确认,甚至阻止某些用户进行交易。
BTC脚本
工作原理
比特币使用一种基于堆栈的脚本语言来处理交易的输入和输出,专门设计用于验证比特币交易的合法性。比特币脚本是非图灵完备的,设计目的是保证交易的安全和简洁。
比特币脚本主要用于在交易输入和输出之间创建验证逻辑,确保只有合法的所有者才能花费比特币。把前一个交易里的输出脚本和当前交易的输入脚本拼在一起执行,没有问题的话就是合法的。
- 输出脚本(ScriptPubKey):在交易输出中定义,指定如何花费该输出。
- 输入脚本(ScriptSig):在交易输入中定义,提供满足输出脚本条件的数据。
- 脚本执行:输入脚本和输出脚本被连接在一起并执行,验证输入脚本是否能解锁输出脚本。
脚本执行过程
当一个比特币交易被广播到网络中时,比特币节点会验证该交易的输入和输出脚本。
- 拼接脚本:将前一个交易的输出脚本(锁定脚本)与当前交易的输入脚本(解锁脚本)拼接在一起,形成一个完整的脚本。
- 执行脚本:在一个基于堆栈的虚拟机中逐条执行脚本指令。
- 堆栈操作:脚本语言使用堆栈进行操作,操作包括将数据推入堆栈、从堆栈中弹出数据、执行哈希运算、签名验证等。
- 验证结果:如果脚本执行完毕且堆栈的顶端元素为真(True),则交易输入被认为是合法的,交易被接受。如果堆栈顶端元素为假(False)或脚本执行过程中出现错误,交易输入被拒绝,交易无效。
Pay-to-PubKey-Hash(P2PKH)
P2PKH是比特币交易中最常见的一种支付方式。它使用公钥哈希(PubKey Hash)来锁定比特币,只有拥有对应私钥的用户才能解锁并花费这些比特币。
工作方式
-
输出脚本(ScriptPubKey):
OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
OP_DUP
:复制堆栈顶元素(公钥)。OP_HASH160
:对公钥进行Hash160(先SHA-256后RIPEMD-160)。<PubKeyHash>
:公钥的哈希。OP_EQUALVERIFY
:比较两个元素是否相等。OP_CHECKSIG
:验证签名是否对应公钥。
-
输入脚本(ScriptSig):
<Signature> <PubKey>
<Signature>
:交易的签名。<PubKey>
:公钥。
示例
- Alice生成交易:Alice将比特币发送给Bob,创建一个P2PKH输出,锁定Bob的公钥哈希。
- Bob花费比特币:Bob创建一个新的交易,引用Alice的交易作为输入,并提供解锁脚本(包含签名和公钥)。
- 验证过程:
- 拼接脚本:
<Signature> <PubKey> OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
- 执行脚本:验证
<PubKey>
的哈希值是否等于<PubKeyHash>
,并验证<Signature>
是否有效。
- 拼接脚本:
Pay-to-Script-Hash(P2SH)
P2SH允许比特币地址代表任意的脚本条件,而不是简单的公钥哈希。
- 简化复杂脚本的使用:P2SH允许用户使用复杂的条件来花费比特币,例如多重签名、多步骤验证等,而无需发送者理解这些复杂的脚本条件。
- 提高灵活性和安全性:通过P2SH,复杂脚本被隐藏在哈希值中,只有在花费时才会公开,有效保护了脚本的隐私和安全。
- 支持复杂条件:通过P2SH,可以轻松实现多重签名、时间锁定、条件支付等复杂的支付条件,而无需发送者了解具体的实现细节。
- 兼容性和扩展性:P2SH使得新的脚本类型和条件可以被无缝集成到现有的比特币网络中,而不需要对比特币协议进行重大更改。
P2SH交易涉及两个阶段:创建P2SH输出和花费P2SH输出。以下是详细的工作原理:
创建P2SH输出
-
生成赎回脚本(Redeem Script):接收者定义一个复杂的条件脚本,这个脚本包含了花费比特币所需的条件。
-
计算脚本哈希:对赎回脚本进行Hash160(先SHA-256后RIPEMD-160)运算,得到一个脚本哈希值。
-
创建P2SH输出脚本:输出脚本中包含该脚本哈希值,格式如下:
OP_HASH160 <ScriptHash> OP_EQUAL
OP_HASH160
:对后续提供的赎回脚本进行Hash160运算。<ScriptHash>
:赎回脚本的哈希值。OP_EQUAL
:验证计算出的哈希值与提供的哈希值是否相等。
花费P2SH输出
-
创建输入脚本(ScriptSig):花费者创建一个包含解锁条件的输入脚本,其中包括满足赎回脚本条件的数据和赎回脚本本身。
-
输入脚本格式:
<Signature> <PubKey> <RedeemScript>
<Signature>
:满足赎回脚本条件的签名。<PubKey>
:满足赎回脚本条件的公钥(如果需要)。<RedeemScript>
:实际的赎回脚本,包含花费条件。
-
验证过程:
- 拼接输入脚本和输出脚本,形成一个完整的验证脚本。
- 执行脚本时,首先验证赎回脚本的哈希值是否与输出脚本中的哈希值匹配。
- 如果匹配,则执行赎回脚本,验证提供的数据(如签名和公钥)是否满足赎回脚本的条件。
示例
创建P2SH交易
-
Alice生成复杂脚本:Alice想要创建一个多重签名地址,要求Bob和Charlie中的至少两人签名才能花费比特币。赎回脚本如下:
2 <BobPubKey> <CharliePubKey> 2 OP_CHECKMULTISIG
-
计算赎回脚本哈希:
- 赎回脚本经过Hash160运算得到脚本哈希
<ScriptHash>
。
- 赎回脚本经过Hash160运算得到脚本哈希
-
创建P2SH输出:Alice创建一个P2SH输出,将比特币发送到
<ScriptHash>
地址,输出脚本为:OP_HASH160 <ScriptHash> OP_EQUAL
花费P2SH输出
-
Bob和Charlie合作花费比特币:Bob和Charlie创建一个新交易,引用Alice的P2SH输出,并提供如下输入脚本:
<SignatureBob> <SignatureCharlie> 2 <BobPubKey> <CharliePubKey> 2 OP_CHECKMULTISIG
<SignatureBob>
和<SignatureCharlie>
:Bob和Charlie的签名。<BobPubKey>
和<CharliePubKey>
:Bob和Charlie's的公钥。- 赎回脚本
2 <BobPubKey> <CharliePubKey> 2 OP_CHECKMULTISIG
。
-
验证过程:
- 拼接脚本:
<SignatureBob> <SignatureCharlie> 2 <BobPubKey> <CharliePubKey> 2 OP_CHECKMULTISIG OP_HASH160 <ScriptHash> OP_EQUAL
- 验证:首先验证赎回脚本的哈希值与输出脚本中的
<ScriptHash>
匹配,然后执行赎回脚本,验证签名和公钥是否满足条件。
- 拼接脚本:
Proof of Burn
Proof of Burn是一种共识机制,用户通过“烧毁”比特币来证明其执行了特定操作。烧毁比特币的方式是将其发送到一个无法使用的地址(即无私钥地址),使得这些比特币永远无法被花费。
工作方式
- 创建交易:用户创建一个交易,将比特币发送到一个特殊地址,例如以
1Burn
开头的地址。 - 验证烧毁:其他节点验证交易并确认比特币已被发送到烧毁地址。
- 共识证明:用户可以使用烧毁的交易作为证明,参与特定操作或获得奖励。
示例应用
- 发行新币:一些区块链项目使用Proof of Burn机制来发行新币,用户通过烧毁比特币来获得新币的发行权。
- 共识机制:Proof of Burn可以用于证明用户的长期投资承诺,因为烧毁的比特币无法回收。
BTC分叉
硬分叉
硬分叉是对区块链协议进行的重大改变,这种改变与之前版本不兼容。所有参与者必须更新到新版本才能继续参与新链上的交易和区块验证。如果一些节点不更新协议,那么这个分叉就会永久存在,形成两条不同的链。
举个例子:
假设比特币网络中每个块的大小限制是1MB,每个交易大约占250个字节,因此每个块大约可以包含4000个交易。如果我们将块大小扩充到4MB,这将导致硬分叉。
- 影响:旧节点(没有更新协议的节点)将无法识别和接受新节点创建的4MB块。
- 可能存在的问题:交易回放,如果某个用户在A链上进行交易,该交易可能会被重新广播到B链上。
- 解决办法:引入一个chainID(链标识符)来区分不同的链。
软分叉
软分叉是对区块链协议的向后兼容的修改。即使一些节点没有更新到新协议,它们仍然可以接受和验证新节点生成的区块(只要新节点发布的区块,旧节点认为是合法的,那就是软分叉)。软分叉不会造成永久性的链分裂,只会出现临时的分叉,直到所有节点都升级到新协议。
还是这个例子,如果把块大小从1MB调整到0.5MB,那么就会软分叉,因为旧节点也是认新协议的,只会出现临时性分叉,不会有永久性分叉。
引用
区块链中的密码学与安全技术: https://zhuanlan.zhihu.com/p/35649160
Dummies for blockchain: https://zhangli1.gitbooks.io/dummies-for-blockchain/content/chapter1/zai-tan-jiao-yi/mo-ke-er681128-merkle-tree.html
作者:加密鲸拓
版权:此文章版权归 加密鲸拓 所有,如有转载,请注明出处!