05-BTC-实现

学习视频来源:https://www.bilibili.com/video/BV1Vt411X7JF/?p=5
本博客除了包含自己的在学习过程中记录的笔记外,还包含少部分自己扩展的内容,如有错误,敬请指正。

文章目录

  • [1. UTXO](#1. UTXO)
    • [1.1 基于交易的账本](#1.1 基于交易的账本)
    • [1.2 UTXO作用](#1.2 UTXO作用)
    • [1.3 交易费](#1.3 交易费)
    • [1.4 基于账户的账本](#1.4 基于账户的账本)
  • [2. 区块](#2. 区块)
    • [2.1 示例](#2.1 示例)
    • [2.2 字段含义](#2.2 字段含义)
    • [2.3 区块头](#2.3 区块头)
    • [2.4 nNonce局限性](#2.4 nNonce局限性)
    • [2.5 铸币交易](#2.5 铸币交易)
  • [3. 交易合法性验证](#3. 交易合法性验证)
  • [4. 无记忆性](#4. 无记忆性)
    • [4.1 伯努利试验](#4.1 伯努利试验)
    • [4.2 挖矿](#4.2 挖矿)
    • [4.3 举例](#4.3 举例)
  • [5. 比特币总量(2100万个)](#5. 比特币总量(2100万个))
  • [6. 比特币安全性](#6. 比特币安全性)
    • [6.1 偷币](#6.1 偷币)
    • [6.2 分叉攻击](#6.2 分叉攻击)
    • [6.3 自私挖矿(selfish mining)](#6.3 自私挖矿(selfish mining))

1. UTXO

1.1 基于交易的账本

区块链是一个去中心化账本,比特币系统是一个基于交易的账本(transaction-base leger) 。每个区块中都包含转账交易和铸币交易,但是区块链中并哪个地方显示记录某个账户的余额是多少,比特币是通过UTXO(Unspent Transaction Output) 机制来追踪和验证币的所有权与可用性的

在比特币系统中,每笔交易可包含多个输入和多个输出。例如一笔交易可同时向B转账5 BTC、向C转账3 BTC。每个输出一旦被创建,就成为一个UTXO,由其所属交易的哈希值(txid)和在该交易中的输出索引(vout)唯一标识。当B花费其5 BTC时,对应的UTXO(txid, 0)被标记为已花费并从UTXO集合中移除;而C尚未花费的3 BTC,对应的UTXO(txid, 1),仍保留在UTXO集合中,可被未来交易引用。

1.2 UTXO作用

UTXO机制是比特币防止双花问题(double spending)的核心:全节点在内存中维护一个全局的 UTXO 集合,任何新交易要合法,其输入必须引用当前存在于该集合中的 UTXO;若引用的输出已不存在,则说明该币已被花费或根本无效,交易将被拒绝。每笔交易会消耗若干 UTXO(作为输入),同时生成新的 UTXO(作为输出),且所有输入金额之和必须等于所有输出金额之和加上交易手续费(tx_fee)------手续费即为输入与输出之间的差额。

1.3 交易费

为什么要有交易费?如果矿工只有通过铸币交易获得奖励,那么有些矿工可能就不会打包别人的交易,而是只打包自己交易。因为打包别人交易自己获得不到奖励,没什么好处。所以为了激励矿工打包他人交易,比特币引入了交易费机制:用户通过支付手续费竞争区块空间,矿工则优先选择手续费高的交易以最大化收益。目前,矿工收入仍以出块奖励为主,但随着比特币每四年左右的减半机制推进,区块奖励持续下降,交易费将逐渐成为矿工的主要收入来源,从而在长期保障网络安全与去中心化。

21万 X 10分钟 / (60 X 24 X 365天) = 约4年

1.4 基于账户的账本

比特币系统转账交易要说明币的来源防止双花问题,但是以太坊不需要,因为以太坊是基于账户的账本(transaction-base leger),它显示记录账户余额,和现实体验比较接近,比如银行余额。

2. 区块

2.1 示例

2.2 字段含义

这些字段是网页上展示的字段,并不是说这些字段都在交易区块中。

字段 含义
Hash 区块的唯一哈希值(SHA-256),用于标识这个区块。例如:00000-9799d... 是该区块的"指纹"。
Capacity 区块容量利用率,表示当前区块使用了多少空间。这里是 131.17%,说明超过了标准大小(1MB),这是由于 SegWit 技术允许超大区块(通过"weight"计算)。
Distance 从当前时间到该区块生成的时间差。这里是 2h 57m 5s,表示这个区块是在 2 小时 57 分钟前挖出的。
BTC Value 区块内所有交易的总输入价值(单位:BTC),即所有资金的"流入"总量。这里是 6,502.6891 BTC
Value Today 按照当前比特币价格(约 90,000/BTC)换算的美元价值。这里是 ` 596,979,956`。
Average Value 平均每笔交易的价值(BTC)。这里是 2.5794 BTC
Median Value 所有交易金额的中位数(一半交易比它小,一半比它大)。这里是 0.01027459 BTC,说明大多数是小额交易。
Input Value 所有交易的输入总和(即"转出"的总额)。这里是 6,502.73 BTC
Output Value 所有交易的输出总和(即"转入"的总额)。这里是 6,505.86 BTC。注意:输出略大于输入,是因为包含了矿工奖励。
Transactions 区块中包含的交易总数。这里是 2,521 笔。
Witness Tx's 使用 SegWit 的交易数量(支持闪电网络等)。这里是 2,280
Inputs 所有交易的输入个数(即"来源地址"数量)。这里是 5,979
Outputs 所有交易的输出个数(即"目标地址"数量)。这里是 12,817
Fees 所有交易支付的手续费总和。这里是 0.0434 BTC(约 $ 3,954.32)。
矿工奖励 3.13 BTC(基础)+ 0.0434 BTC(手续费)= 3.1734 BTC
区块大小 ~1.37 MB
确认数 18 次(非常安全)
挖矿难度 极高(约 1.46e14)

2.3 区块头

cpp 复制代码
class CBlockHeader
{
public:
    // 版本号
    int32_t nVersion;
    // 前一区块哈希(uint256 是 256-bit 哈希类型)
    uint256 hashPrevBlock;
    // Merkle 根
    uint256 hashMerkleRoot;
    // 时间戳
    uint32_t nTime;
    // 难度目标(target)
    uint32_t nBits;
    // 随机数
    uint32_t nNonce;
};

2.4 nNonce局限性

由于目前挖矿的人越来越多,挖矿的难度已经很高。而nNonce是一个32位的无符号整数,当前就算枚举其所有的值,大概率还是找不到符合条件的哈希,所以只能调整其他几个字段的值:

  • nVersion、hashPrevBlock:不能调整。
  • -nTime: 系统不要求非常准确的时间,可以适当调整,只要别太离谱。
  • nBits:只能按照协议中的要求定义进行调整,不能调整。
  • nNonce:可以调整。
  • hashMerkleRoot:可以调整。 默克尔根。每个区块中可以包含铸币交易,可以通过调整铸币交易中的coinBase域,进而调整默克尔根。

2.5 铸币交易


铸币交易没有输入地址,因为币是凭空造出来的。输入有一个coinBase域,可以写入任何内容 。如果我们改变这里的内容,会影响默克尔根,所以如果nNonce不够用,我们可以把coinBase前8个字节用来用枚举,空间一下就大了很多。真正挖矿的时候有两层循环。外层循环coinBase,算出默克根后,内层循环再调整nNonce。

3. 交易合法性验证

比特币通过脚本系统验证交易合法性:每笔输入包含一个 sigScript(解锁脚本),它与所引用UTXO的前一笔交易中的 pkScript(锁定脚本)拼接后,在虚拟机中执行;若脚本成功运行且最终结果为真,则交易合法;否则视为无效。

4. 无记忆性

4.1 伯努利试验

伯努利试验(Bernoulli trial)是指只有两种可能结果(如"成功"或"失败")且每次试验相互独立、成功概率恒定的随机实验,典型例子是掷硬币------无论之前出现多少次正面,下一次正面朝上的概率始终是 1/2,这体现了其无记忆性(memorylessness)。多个独立同分布的伯努利试验构成一个伯努利过程(Bernoulli process)。

4.2 挖矿

在比特币挖矿中,每一次尝试不同的 nonce 值可视为一次伯努利试验:成功概率极低(因为目标阈值 target 非常小),但矿工每秒可进行数十亿次尝试。由于试验次数极大、单次成功概率极小,单位时间内成功挖出区块的次数近似服从泊松分布(Poisson distribution),而两次出块之间的等待时间则服从指数分布(exponential distribution),其均值为 10 分钟。

指数分布同样具有无记忆性:即使已经连续挖了 20 分钟仍未出块,预期还需等待的时间仍然是 10 分钟,过去的时间不影响未来。这一性质对区块链的公平性至关重要------它确保了矿工获得记账权的概率与其算力占比严格成正比。例如,若某矿工拥有全网 1% 的算力,则长期来看,他平均每挖到 1 个区块需等待约 1000 分钟(100 × 10 分钟),且不会因持续尝试而获得超额优势。

如果某个加密货币的出块机制不满足无记忆性,就可能导致算力强者获得不成比例的收益。比如算力是对手10倍的矿工,实际出块频率可能远超10倍,从而破坏去中心化和激励公平性。比特币通过基于 PoW 的随机性和指数分布的无记忆性,有效避免了这一问题,保障了系统的长期稳定与抗中心化。

4.3 举例

矿工A:算力=90%

矿工B:算力=10%

  • 满足无记忆性
    记账权按算力比例分配,获得记账权的概率A:B = 9:1
  • 不满足记忆性
    系统设定每10分钟必须出一个块,记账权按算力比例分配。一旦开始尝试,就逐步接近成功(类似"进度条")。
    A 每次都能快速推进"进度条",几乎总是在10分钟内完成;B虽然也有机会,但进度太慢,经常被 A 抢先完成;
    更糟的是:如果 A 在上一轮刚出完块,下一轮他依然立刻开始高速推进,而 B 还在缓慢爬行。
    结果:A 的出块频率可能达到 95% 甚至 99%,远超其 90% 的算力占比。

5. 比特币总量(2100万个)

21万 X 50 +21 X 25 + 21万 X 12.5 + ... = 21万 X 50 X(1+1/2+1/4 + ...) = 2100万。

挖矿就是比拼算力,挖矿本身是没有意义的,但它对于维护系统的安全性是至关重要的。所以有一种说法:Bitcoin is secured by mining。只要大部分算力是集中在诚实节点手里,系统的安全性就能得到保证。

6. 比特币安全性

6.1 偷币

如果恶意节点试图窃取用户A的比特币,例如将A拥有的UTXO转移到自己的地址,它必须构造一笔包含该UTXO作为输入的交易,并提供有效的签名以满足原输出的锁定脚本(如 P2PKH 中的公钥哈希验证)。然而,由于数字签名依赖于A的私钥,而私钥无法被伪造,恶意节点无法生成合法的 sigScript。即使它将这笔无效交易打包进自己挖出的区块并广播,其他全节点在验证时会执行脚本:要么因签名不匹配、公钥哈希不符而失败,要么因引用的UTXO不存在或已被花费而被判定为非法。一旦验证失败,整个区块将被拒绝,所以偷币不会成功。

6.2 分叉攻击

分叉攻击会造成double spending。如用户A向电商平台支付比特币购买商品,在交易被打包进一个区块并被商家接受后,A立即秘密构建一条替代链,在该链中将同一笔资金重新发送给自己(或另一个地址)。如果A能让这条私有链比公开主链更长,根据比特币"最长合法链"原则,网络最终会接受私有链,导致原始支付交易被回滚,从而实现"既拿到商品,又拿回比特币"的double spending。

然而,要成功实施此类攻击,攻击者必须在诚实网络继续扩展主链的同时,连续赢得多个区块的记账权,但是连续赢得多个区块的记账权的概率是很小的。因此,比特币社区普遍采用 "6 个确认" ------即等待包含该交易的区块之后再追加 6 个区块(约 60 分钟)。除非攻击者拥有很大的算力,否则回滚交易在经济和概率上都极不现实。

6.3 自私挖矿(selfish mining)

一种由算力较大的矿工或矿池采用的策略性攻击:当其挖到一个有效区块时,并不立即广播,而是秘密继续在该区块上挖矿,试图构建一条比公开主链更长的私有链。在此期间,诚实矿工仍在原链上挖矿。一旦自私矿工的私有链领先公开链至少两个区块,他们便一次性将私有链全部发布,由于比特币节点总是选择最长有效链,网络会抛弃原主链并切换到自私矿工的链上,使其获得这些区块的全部奖励。

这种策略仅在矿工掌握足够大算力时才会成功,而且即便成功收益也有限,因为实施成本高、易被监测。但是如果一旦失败,即私有链被诚实网络追上并超越,挖出的区块将全部作废,损失所有隐藏区块的奖励;

相关推荐
咸鱼时日翻身5 小时前
区块链私有链实习心得
区块链
Light606 小时前
智链护航,数档永存:基于领码SPARK平台构建下一代AI+区块链档案系统解决方案
人工智能·spark·区块链
DICOM医学影像21 小时前
3. go语言从零实现以太坊客户端 - 查询合约中账户余额
golang·区块链·智能合约·solidity·以太坊·web3.0
WZgold1411 天前
黄金再创新高!2026 年金价走势预测
大数据·人工智能·经验分享·区块链
DICOM医学影像1 天前
4. go语言从零实现以太坊客户端 - 区块链转账
golang·区块链·以太坊·web3.0·geth
Tancenter1 天前
区块链关键技术
区块链·哈希算法·数字签名
CryptoPP1 天前
对接API库 获取印度股票历史数据
金融·数据挖掘·数据分析·区块链
CryptoRzz2 天前
印度尼西亚(IDX)股票数据对接开发
java·后端·websocket·web3·区块链
DICOM医学影像2 天前
2. go语言从零实现以太坊客户端-查询区块链账户余额
开发语言·golang·区块链·以太坊·web3.0·hardhat