基本算法
SHA-256
这是比特币挖矿中使用的核心哈希算法,即安全哈希算法(SHA,Secure Hash Algorithm)的一种。SHA-256能生成出一个256位的哈希值,适用于工作量证明(Proof of Work,PoW)的系统中。
RIPEMD-160
比特币使用RACE Integrity Primitives Evaluation Message Digest(RIPEMD)的一个160位版本,主要用于比特币地址的创建过程中。
Base58
这是一种用于表示比特币地址的编码方式。Base58编码可以排除视觉上容易混淆的字符,如数字'0’和字母’O’。
Elliptic Curve Digital Signature Algorithm(ECDSA)
比特币使用了椭圆曲线数字签名算法(ECDSA)来实现面向公开网络的私钥签名和公钥验证。
Merkle Trees
用于验证数据是否被篡改,可以高效地组织和验证大量的信息。比特币中的交易信息被组织成Merkle树,存在于每个区块的头部信息中。
基本数据结构
区块数据结构
区块头 Block Headers
| 字节数 | 名称 | 数据类型 | 描述 |
|---|---|---|---|
| 4 | 版本 | int32_t | 区块版本号指示遵循哪套区块验证规则。具体请参阅下面的区块版本列表。 |
| 32 | 之前区块头部哈希 | char[32] | 是前一个区块头部的SHA256哈希,其内部字节顺序。这确保没有任何前一个区块可以在不同时改变此区块的头部的情况下被改变。 |
| 32 | 当前区块哈希Merkle root hash | char[32] | SHA256哈希,其内部字节顺序。默克尔根由此区块中包含的所有交易的哈希衍生,确保没有任何交易可以在无修改头部的情况下被修改。请参阅下方的默克尔树章节。 |
| 4 | 时间戳 | uint32_t | 区块时间是矿工开始哈希头部时的Unix时间。必须严格大于之前11个区块的时间中位数。完全节点将不接受头部时间超过其时钟未来两小时的区块。 |
| 4 | 难度值nBits | uint32_t | 目标阈值的编码版本,此区块的头部哈希必须小于或等于。注:请参阅下方描述的nBits格式。 |
| 4 | 工作量证明nonce | uint32_t | value used in proof-of-work |
区块版本 Block Versions
- Version 1 创世区块(2009 年 1 月)推出。
- Version 2 在比特币核心 0.7.0(2012 年 9 月)中作为软分叉引入。如 BIP34 所述,有效的版本 2 区块需要在 coinbase 中设置一个区块高度参数。BIP34 中还描述了拒绝某些区块的规则;根据这些规则,Bitcoin Core 0.7.0 及以后的版本在区块高度 224,412 时(2013 年 3 月)开始拒绝在 coinbase 中没有区块高度的版本 2 区块,并在三周后的区块高度 227,930 时开始拒绝新的版本 1 区块。
- Version 3 在比特币核心 0.10.0(2015 年 2 月)中作为软分叉引入。当分叉达到完全执行时(2015 年 7 月),它要求在新区块中对所有 ECDSA 签名进行严格的 DER 编码,如 BIP66 中所述。自 Bitcoin Core 0.8.0(2012 年 2 月)以来,不使用严格 DER 编码的交易之前一直是非标准的。
- Version 4 BIP65 中指定并在 Bitcoin Core 0.11.2(2015 年 11 月)中引入的第 4 版区块作为软分叉于 2015 年 12 月开始启用。这些区块现在支持该 BIP 中描述的新操作码
OP_CHECKLOCKTIMEVERIFY
区块体 Block Body
区块体包含整个区块的交易信息。这是一个包含所有交易信息的表格。
| 字节数 | 名称 | 数据类型 | 描述 |
|---|---|---|---|
| VarInt | txn_count | var_int | 交易数量,表示这一区块里的交易数量,该字段的大小不固定,可能是1字节,也可能是2字节,3字节,根据实际的交易数量而定。 |
| txns | Transaction[]结构参考 交易数据结构 章节 | 记录这一区块里所有的交易,主要包含交易的输入和输出。 |
区块链结构

交易数据结构
Transaction
| 数据类型 | 名称 | 描述 |
|---|---|---|
| i32 | version | 协议版本 |
| TransactionInput | inputs | |
| TransactionOutput | outputs | |
| u32 | lock_time | 交易的锁定时间,表示这一交易被锁定的时间 |
TransactionInput
| 数据类型 | 名称 | 描述 |
|---|---|---|
| OutPoint | previous_output | 上一笔交易输出 |
| Bytes | script_sig | 解锁脚本这是一个由"解锁"条件构成的脚本,包括解锁特定script_pubkey所需的所有元素,如签名和公钥。 |
| u32 | sequence | 序列号 |
| script_witness | 见证脚本 隶属于SegWit(Segregated Witness),用于增强比特币的可扩展性和交易速度。 |
OutPoint
| 数据类型 | 名称 | 描述 |
|---|---|---|
| Hash256 | hash | 交易ID |
| u32 | index | 输出索引,表明是交易中的第几个输出 |
TransactionOutput
| 数据类型 | 名称 | 描述 |
|---|---|---|
| u64 | value | 输出金额 |
| Bytes | script_pubkey | 锁定脚本定义花费比特币的条件。处于交易输出的自由比特币只能被包含这些条件的交易账户花费。一般来说,这些条件包括的是一个公钥的哈希值和一个验证签名的比特币脚本。 |
安全问题
如何保证区块不被恶意修改?
每个Block Headers中包含2个hash信息:
之前区块的Block Headers 信息Hash
当前区块的交易记录信息Hash
当你修改当前的区块信息,就需要修改当前区块后到所有区块信息。
既然是去中心化的分布式架构,如何确定由谁来添加区块数据?
在学习区块链之前,我在微服务领域了解的共识算法都属于“分配”关系,但是在BTC中引入了**工作量证明(proof-of-work)**和矿工奖励,将添加区块数据这样的共识操作变为了“竞争”关系
这个工作量证明算法指的用SHA256算法不断地对区块头和—个随机数字进行哈希计算, 直到出现—个和预设值相匹配的解。第—个找到这个解的矿工会赢得 这局竞赛并会将此区块发布到区块链中。
– 《Mastering Bitcoin》
为了方便理解概念,举个不恰当的例子过程大概是:
矿工需要找出一段文本,原始文本要求是 Block Headers Hash+随机数 段文本经过SHA256后 前Nonce位都是0”
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
)
func main() {
blockHeader := "我是区块头数据"
difficultyTarget := "0000"
nonce := 0
for {
inputData := fmt.Sprintf("%s%d", blockHeader, nonce)
hashInstance := sha256.New()
hashInstance.Write([]byte(inputData))
hashValue := hex.EncodeToString(hashInstance.Sum(nil))
if hashValue[:4] == difficultyTarget {
fmt.Printf("找到满足条件的Nonce了:%d,对应的哈希值是:%s\n", nonce, hashValue)
break
}
nonce++
}
}
关于矿工奖励
矿工们在挖矿过程中会得到两种类型的奖励: 创建新区块的新币奖励, 以及区块中所含交易的交易费。为了得到这些奖励, 矿工们争相完成—种基于加密哈希算法的数学难题, 这些难题的答案包括在新区块中, 作为矿工的计算工作量的证明, 被 称 为”“工作量证明”。
该算法的竞争的机制以及获胜者有权在区块链上进行交易记录的机制, 这二者比特币安全的基石。 新比特币的生成过程被称为挖矿是因为它的奖励机制被设计为速度递减模式, 类似于贵重金属的挖矿过程。
比特币的货币 是 通过挖矿发行的 , 类似于中央银行通过印刷银行纸币来发行货币。矿工通过创造—个新区块得到的比特币数量大约每四 年 (或准确说是每隔210 ,000个块) 减少—半。
开始时为2009年1月每个区块奖励50个比特币, 然后到2012年11月减半为每个 区块奖励25个比特币。之后将在2016年的某个时刻再次减半为每个新区块奖励12 .5个比特币。
基于这个公式, 比特币挖矿 奖 励以指数方式递减, 直到2140年。届时所有的比特币 (20 ,999 ,999 ,980) 全部发行完毕。换句话说在2140年之后, 不会 再 有新的比特币产生。
矿工们同时也会获取交易费。每笔交易都可能包含—笔交易费 , 交易费是每笔交易记录的输入和输出的差额。在挖矿过程 中“挖出”新区块的矿工获胜者可以得到该区块中包含的所有交易“小费”。
目前, 这笔费用占矿工收入的0 .5%或更少, 大部分 收益仍来自挖矿所得的比特币奖励。然而随着挖矿奖励的递减, 以及每个区块中包含的交易数量增加, 交易费在矿工收益 中 所占的比重将会逐渐增加。在2140年之后, 所有的矿工收益都将由交易费构成。 “挖矿”这个词有—定的误导性。它容易引起对贵重金属采矿的的联想 , 从而使我们的注意力都集中在每个新区块产生的奖励 上。
尽管挖矿带来的奖励是—种激励, 但它最主要的目的并不是奖励本身或者新币的产生。如果只把挖矿看作生产新币的过 程, 那你是把手段 (激励措施) 当成了目的。挖矿是—种将结算所去中心化的过程, 每个结算所对处理的交易进行验证和 结 算。挖矿保护了比特币系统的安全, 并且实现了在没有中心机构的情况下, 也能使整个比特币网络达成共识。
挖矿这个发明使比特币变得很特别 , 这种去中心化的安全机制是点对点的电子货币的基础。铸造新币的奖励和交易费是— 种 激励机制 , 它可以调节矿工行为和网络安全, 同时又完成了比特币的货币发行。
– 《Mastering Bitcoin》
关于难度调整
比特币的区块平均每10分钟生成—个。这就是比特币的心跳 , 是货币发行速率和交易达成速度的基础。不仅是在短期内, 而 是在几十年内它都必须要保持恒定。
在此期间, 计算机性能将飞速提升。此外, 参与挖矿的人和计算机也会不断变化。为了 能让新区块的保持10分钟—个的产生速率 , 挖矿的难度必须根据这些变化进行调整。
事实上, 难度是—个动态的参数, 会定 期调整以达到每10分钟—个新区块的目标。简单地说 , 难度被设定在 , 无论挖矿能力如何 , 新区块产生速率都保持在10分 钟 —个。 那么 , 在—个完全去中心化的网络中, 这样的调整是如何做到的呢? 难度的调整是在每个完整节点中独立自动发生的。
每 2 ,016个区块中的所有节点都会调整难度。难度的调整公式是由最新2 ,016个区块的花费时长与20 ,160分钟 (两周, 即这些 区 块以10分钟—个速率所期望花费的时长) 比较得出的。难度是根据实际时长与期望时长的比值进行相应调整的 (或变难 或变易) 。简单来说, 如果网络发现区块产生速率比10分钟要快时会增加难度。如果发现比10分钟慢时则降低难度 。
如果多个矿工同时完成了工作量证明该怎么办?
google:
“Longest Chain Rule” 最长链原则
“Blockchain Fork” 区块链分叉
假设有A B C个矿工,A B同时完成了工作量证明的问题并分别创建了新的区块(BlockA BlockB)。 那么会保留BlockA BlockB,并且A B进入竞赛,看谁算的比对方快(区块链更长)。 在A B竞赛的过程中,C可以选择在BlockA or BlockB 的基础上继续进行”挖矿“。C的选择也对“竞赛”的结果有影响(谁更长)。