双重支付问题 (Double-Spending Problem)
BTC中的公私钥解决了证明所有权和授权交易两个部分。私钥是你对某个地址下数字资产的唯一所有权证明,而数字签名是对一笔交易的、不可否认的授权。这套体系保证了只有你才能动用你的钱,别人伪造不了你的签名。但它只解决了“这笔交易是不是你本人同意的”这个问题。
数字世界和物理世界的根本区别在于可复制性。我有一个代表“1个币”的数字文件。我可以把它复制一百万份,每一份都和原始文件一模一样。那么一个只有公私钥的系统就会面临以下的问题:
- 我拥有一个“币”,我的私钥能证明我拥有它。
- 我创建了一笔交易:“我将这个币支付给商家A”。我用我的私钥对这笔交易进行了签名。商家A收到了这笔交易,验证了我的签名,确认有效。
- 问题来了:在把交易发给A的同时(或者之后),我完全可以把**原始的那个“币”**再用一次,创建第二笔交易:“我将这个币支付给商家B”。我同样用我的私钥签名,商家B验证后也发现签名有效。
A和B都收到了一个密码学上完全有效的“支付凭证”。他们都认为自己收到了那个币。这个币到底属于谁?系统里并没有一个公认的、统一的记录来判定哪笔交易在先,哪笔交易无效。这就是双重支付问题。
那么,必然要有一个账本。这个账本要么记录了历史交易,要么记录钱当前在谁的手里,不论如何需要记录。这个账本在传统的中心化支付系统中,由一个中心服务器来完成这个工作,并且这样往往能得到高效的体验。在这里,货币的发行和交易验证,必须通过这个中心化的服务器来完成。
而在去中心化的解决方案中,要解决两个问题:
- 谁有权利发行数字货币?
- 如何验证交易的有效性和安全性?
在BTC中,发行货币是由挖矿决定的。而验证交易也是维护一个交易表,不过细节有所不同。
交易(Transaction)
BTC的每一笔交易,都可以分为如下两个部分:
- 输入 (Inputs)
- 输出 (Outputs)
输入(Input)
输入部分负责回答“这笔交易要花的钱是来自哪里的?”这个问题。
- 无账户机制:比特币没有“账户”或“余额”的概念。相反,你的钱包里装的是一堆“数字支票”或“待消费的账单”,这些被称为UTXO (Unspent Transaction Output - 未花费的交易输出)。
- 必须讲清楚输入来源:每一个“输入”都是对之前某笔交易的“输出”的引用。它实质上是在说:“我要动用我之前收到的那笔钱(某个UTXO)。”
- 包含解锁脚本:为了证明你有权花费这个UTXO,输入部分必须包含一个“解锁脚本”,这通常就是你的数字签名和你的公钥。这相当于在支票上签字,证明你是这笔钱的合法主人。
输入部分包含这三个关键信息:
- 发送方的比特币地址 (Sender's Address(es)): 这笔交易花的是哪个或哪些地址上的钱。这些地址从此就被公开地关联在了一起。例如,如果A用了两个地址上的钱来凑够支付给B的金额,那么全世界都会知道这两个地址属于同一个人(或实体)。
- 发送方的完整公钥 (Sender's Full Public Key): 在花费的那一刻,A必须公开他的公钥,以便全网节点验证这个公钥确实能匹配他花费的那个地址,并且能验证他的签名。
- 发送方的数字签名 (Sender's Digital Signature): A用自己私钥生成的、对这笔特定交易的授权签名。这个签名本身虽然不能暴露私钥,但它也是公开数据。
输出(Output)
输出部分负责回答“这笔花出去的钱将变成什么样的新形式?”这个问题。
- 创建新的UTXO:每一个“输出”都会创建一个全新的、可以被未来交易花费的UTXO。
- 包含锁定脚本:每个输出都包含两个关键信息:
- 金额:这个新的UTXO值多少比特币。
- 锁定脚本 (Locking Script):这是一个“谜题”或“锁定条件”,规定了谁有权在未来花费这个UTXO。通常,这个脚本会包含接收方的比特币地址(实际上是其公钥的哈希),意味着只有拥有对应私钥的人才能解开这个锁。
一笔交易通常至少有以下输出:
- 接收方的比特币地址 (Recipient's Address): B用来收款的那个地址。
- 转账金额: 明确记录了B的地址收到了多少比特币。
- 找零地址和金额 (Change Address and Amount): 如果A支付的钱大于需要转给B的金额,通常会有一笔找零退回到A的一个新地址。这个找零地址和金额也是公开的。这又创建了一条新的关联线索。
因此,在区块链中有两种哈希指针,一种是保持区块链防篡改性的指针,另一种是指向输入来源的哈希指针。
在交易中,当且仅当A决定要花费这个地址上的比特币时,A的公钥必须被公开给全世界。即,当A创建一笔新的交易来花费这些钱时,他必须向网络证明他就是这笔钱的主人。交易的**输入部分(解锁脚本)**必须包含三样东西:
- A的数字签名:由A的私钥生成。
- A的完整公钥:这个公钥就是之前被哈希成地址的那个原始公钥。
- A的BTC地址:保证公钥的验证是正确的。
需要注意的是,当B(或其他人)只是知道A的比特币地址时,他们并不知道A的公钥,当A花费开始前,没有任何人知道A的公钥,只知道地址,因为地址是公钥的哈希。
脚本验证(Script Validation)
明确了输入和输出后,我们再来看BTC的一个交易验证过程:
- 锁定脚本 (Locking Script, or
scriptPubKey
) 存在于前一个交易的“输出” (UTXO) 中。当有人付钱给你时,他创建的这个输出就包含了一个锁定脚本。在一个标准的交易中,这个脚本相当于一个数学谜题,大意是:“只有能提供与这个地址(公钥哈希)匹配的公钥,并且能用对应私钥生成有效签名的人,才能动用这笔钱。” - 解锁脚本 (Unlocking Script, or
scriptSig
) 存在于你现在要创建的这笔新交易的“输入”中。它负责提供解开上述“锁”的答案。在一个标准交易中它包含完整公钥和数字签名两部分
当要花费一笔钱时,你创建一笔新交易并将其广播出去。网络中的每一个验证节点(矿工)收到后,都会执行以下操作来确认你是否真的有权花费这笔钱:
- 取出锁定脚本:节点根据你新交易输入中引用的信息,找到它所花费的那个UTXO,并从中提取出锁定脚本 (
scriptPubKey
)。 - 取出解锁脚本:节点从你新交易的输入中,提取出解锁脚本 (
scriptSig
)。 - 拼接脚本:节点会将解锁脚本放在前面,锁定脚本放在后面,将它们拼接成一个临时的、单一的执行脚本。
组合脚本 = [你的解锁脚本] + [旧的锁定脚本]
Combined_Script = [scriptSig] + [scriptPubKey]
- 执行脚本:
- 节点会调用比特币的脚本执行引擎,从头到尾执行这个组合脚本。
- 这是一个基于“栈”的简单计算过程:
- 第一步(钥匙部分执行):你的解锁脚本会先把你的签名和公钥推到计算栈上。
- 第二步(锁部分执行):紧接着,旧的锁定脚本开始执行。它会利用栈上已经存在的签名和公钥,进行一系列操作,例如:复制公钥、哈希公钥、与地址比对、验证签名等(例如
OP_DUP
,OP_HASH160
,OP_EQUALVERIFY
,OP_CHECKSIG
)。
- 得出结果:如果整个脚本顺利执行完毕,并且最终栈顶留下的结果是
TRUE
(或非零值),那么验证通过。这意味着你的“钥匙”完美地解开了那个“锁”。
- 判定交易有效性:如果验证通过,节点就确认这笔交易的这个输入是合法的,并继续检查交易的其他部分。如果验证失败(比如签名错误、公钥不匹配,导致脚本执行中断或最终结果为
FALSE
),则整个交易被视为无效,并被网络拒绝。
区块(Block)
从结构上讲,比特币的每一个区块(Block)都可以清晰地分为两个主要部分:
- 区块头 (Block Header)
- 区块体 (Block Body)
区块头 (Block Header)
区块头是每个区块最核心的部分,它的大小是固定的(80字节),包含了关于这个区块的元数据和摘要信息。它就像一本书的封面和版权页,提供了所有关键的索引信息,但不包含具体内容。
区块头包含以下六个字段:
- 版本号 (Version):指明了该区块所遵循的验证规则。
- 上一个区块的哈希 (Previous Block Hash):一个指向前一个区块头的哈希指针。正是这个字段,将所有区块像链条一样一个接一个地串起来,形成了“区块链”。这是保证数据不可篡改的关键。
- 默克尔根 (Merkle Root):一个代表了该区块内所有交易的、独一无二的加密哈希。它高效地总结了区块体内的所有交易数据,并能快速验证某笔交易是否存在于该区块中。
- 时间戳 (Timestamp):该区块被矿工挖出的大致时间。
- 难度目标 (Difficulty Target):一个数字,规定了有效的工作量证明哈希必须小于这个值。网络通过调整这个值来控制挖矿难度。
- 随机数 (Nonce):矿工在挖矿过程中,需要不断尝试和改变的数字。找到一个能使整个区块头的哈希值小于难度目标的Nonce,是完成工作量证明的关键。
矿工挖矿时进行哈希计算的对象是这个80字节的区块头。
区块体(Block Body)
区块体占据了区块绝大部分的存储空间,它包含了这个区块确认的所有交易的完整列表。
- 交易计数器 (Transaction Counter):一个简单的计数器,表明这个区块中包含了多少笔交易。
- 交易列表 (Transactions):按照特定格式记录的、该区块内所有被确认的交易的详细信息。一笔笔交易(包含了输入、输出、签名等)就存放在这里。
区块体的大小是可变的,取决于其中包含了多少笔交易,目前比特币区块的大小上限大约在4MB左右。
Coinbase域
在比特币的每一个区块中,都包含了一系列交易。而第一笔交易必须是、且只能是一笔Coinbase 交易。
这笔交易非常特殊,因为它不是由普通用户发起的,而是由成功挖出这个区块的矿工(或矿池)自己创建的。
它的主要目的有两个:
- 领取区块奖励:矿工通过这笔交易来领取他们应得的奖励。这个奖励包含两部分:
- 区块补贴 (Block Subsidy):凭空创造出来的、全新的比特币。这是新比特币进入流通的唯一途径。(例如,在2024年减半后,这个补贴是3.125 BTC)。
- 交易手续费 (Transaction Fees):该区块内所有其他交易的手续费总和。
- 记录特殊数据:这笔交易的结构很特别,允许矿工在其中嵌入一些自定义数据,即“Coinbase 域”。
与普通交易不同,Coinbase交易没有输入(因为它是在创造新钱,而不是花费旧钱),只有输出(将奖励付给矿工的地址)。“Coinbase 域”(技术上更准确的叫法是 Coinbase 交易输入中的 scriptSig
字段,也常被称为“Coinbase data”)是 Coinbase 交易中最有趣、功能最丰富的部分。
因为 Coinbase 交易没有前置的交易需要解锁,所以这个通常用来存放解锁脚本(如签名和公钥)的地方,就可以被矿工用来自由地写入2到100字节的任意数据。这个空间,在挖矿过程中扮演着几个至关重要的角色:
1. 存储 ExtraNonce(额外的随机数)- 最重要的技术用途
- 背景:矿工挖矿,本质上是在寻找一个随机数(Nonce),将它与区块头(Block Header)的其他数据组合后进行哈希运算,使得最终的哈希值小于一个特定的目标值。
- 问题:区块头里留给 Nonce 的空间只有4个字节,这意味着只有大约42.9亿种可能性。对于现代强大的ASIC矿机来说,这点可能性在不到一秒钟内就会被全部尝试完毕。
- 解决方案:当42.9亿次尝试都失败后,矿工需要改变区块头的某些数据来重新开始计算。如果去改变区块里的交易,计算量会很大。最聪明的办法,就是去改变 Coinbase 交易里的“Coinbase 域”。
- ExtraNonce:矿工在这个域里设置一个计数器,称为“ExtraNonce”。每次区块头的 Nonce 用完后,他们就将 ExtraNonce 加1。这个小小的改动会改变 Coinbase 交易的哈希值,从而改变整个区块的默克尔树根(Merkle Root),最终改变了区块头。这样,矿工就得到了一个全新的计算任务,可以继续进行下一个42.9亿次的哈希尝试。
2. 身份标识 (Miner/Pool Identification)
矿工或矿池通常会把自己的名字或独特的标识字符串写进 Coinbase 域。这就像艺术家在自己的画作上签名一样。当你浏览比特币区块浏览器时,经常会看到区块信息里标注着“由 AntPool 开采”或“由 F2Pool 开采”,这些信息正是从该区块的 Coinbase 域里读取的。
3. 协议投票与信令 (Signaling)
这是 Coinbase 域在比特币治理中非常重要的作用。当社区有新的技术升级提案(即BIP, Bitcoin Improvement Proposal)需要部署时,特别是软分叉,需要得到大部分矿工的算力支持。
矿工们可以通过在他们挖出的区块的 Coinbase 域中包含特定的数据(比如写入“/BIP91/”或特定的比特位),来公开“投票”,向全网宣告他们支持并准备好激活某项新功能。当支持某个提案的区块在一段时间内达到一定比例(例如95%)时,该提案就会被锁定并最终激活。SegWit 的激活过程就是一个著名的例子。
4. 记录区块高度 (Block Height)
根据 BIP 34 提案的要求,Coinbase 域的开头必须包含当前区块的高度。这样做可以防止两个不同的区块产生完全相同的 Coinbase 交易哈希值,增强了协议的稳健性。
节点(Node)
全节点(Full Node)
全节点是整个比特币网络的基石和守护者。它们承担着最完整的责任。
- 存储数据:下载并存储全部的区块链历史数据(从创世区块到最新的区块)。
- 核心功能:
- 独立验证:独立地验证网络中的每一笔交易和每一个区块,并根据比特币的共识规则(例如,检查双重支付、验证数字签名、确认区块奖励是否正确等)来判断其有效性。
- 强制执行规则:拒绝不符合共识规则的交易和区块,从而保护网络不受攻击和欺骗。
- 服务网络:向其他节点(尤其是轻节点)提供区块链数据和验证服务。
- 信任模型:无需信任 (Trustless)。因为它们自己持有并验证了所有数据,所以它们不需要信任网络中的任何其他参与者。
轻节点 (Light Node / SPV Node)
轻节点是绝大多数普通用户在手机或桌面钱包上运行的节点类型。它们为了便利性牺牲了一部分的去中心化和安全性。
- 存储数据:只下载和存储区块头 (Block Headers),而不下载包含所有交易的庞大区块体。区块头非常小(每个80字节),所以资源消耗极低。
- 核心功能:
- 查询交易:当需要验证一笔与自己相关的交易时,它无法独立完成。
- SPV验证 (Simplified Payment Verification):它会向一个或多个全节点请求帮助,索要这笔交易的默克尔证明 (Merkle Proof)。通过这个简短的证明,轻节点可以验证这笔交易确实存在于某个区块中,并且被全网所接受。
- 信任模型:需要信任。它需要信任为它提供数据的全节点没有撒谎(比如,隐瞒一笔双重支付交易)。为了降低风险,轻节点通常会连接到多个全节点。
中本聪共识 (Nakamoto Consensus)
在BTC中,一个问题是,谁有资格创建新节点?一个直观的思路是使用投票机制。
设想一个最简单的投票系统:网络中的每个节点都有一票,大家对“下一个区块应该是哪个”进行投票,少数服从多数。但是这个简单的投票系统在BTC中很容易受到女巫攻击。
- 身份的廉价性:在一个开放网络中,任何人都可以轻易地、近乎零成本地创建出成千上万个虚假的节点(女巫身份)。
- 攻击方式:一个攻击者可以轻松地创建出比网络中所有诚实节点加起来还要多的虚假节点。然后,他可以用这些“女巫节点”投票,轻松地控制整个网络的决策,比如只确认自己的交易、阻止别人的交易,甚至进行双重支付
所以,在一个匿名和开放的系统中,“一人一票”是无效的,因为我们无法可靠地验证“一人”这个身份。
工作量证明 (Proof-of-Work)
为了让投票机制有效,我们必须让“投票权”变得稀缺且难以伪造。也就是说,投票必须与某种有价值的、难以轻易复制的资源相绑定。在BTC中,中本聪使用的是工作量证明 (Proof-of-Work)机制。
- 投票权:算力 (Hash Power)。你的算力越强,你“投中”下一个区块(即率先解出谜题)的概率就越大。
- 如何防范女巫攻击:创建再多的虚假节点也没用,因为它们没有算力,就相当于没有投票权。攻击者必须投入真金白银购买矿机、消耗电力,才能获得与诚实矿工相抗衡的“算力票”。这使得攻击成本极其高昂。
- 可以看作:“一CPU一票”(One-CPU-One-Vote),而不是“一人一票”。
这实际上是一种记账权的竞赛。它设定了一个极其困难但验证起来却非常容易的数学难题,让全球的计算机(矿工)去竞争解决。
- 目标:第一个找到有效答案的矿工,将获得创建下一个区块的权利。
- 过程:
- 矿工将待确认的交易打包成一个“候选区块”。
- 他们对这个区块的“区块头”(一个80字节的数据块)进行哈希运算。
- 他们的任务是,通过不断改变区块头中的一个随机数(Nonce),来寻找一个能让整个区块头的哈希值小于某个“难度目标”的解。
- 由于哈希函数的特性,这个过程没有任何捷径,只能靠海量的、疯狂的暴力猜测。这需要消耗巨大的计算能力和电力,也就是所谓的“工作量”。
- 作用:PoW机制确保了创建区块的成本极高,从而使得篡改历史数据(需要重新计算之后所有区块的工作量)在经济上变得不可行,保证了区块链的安全性。
交易合法性检查
仅仅完成工作量证明是不够的。一个矿工创建的新区块,还必须严格遵守比特币协议中定义的一系列验证规则,才能被网络中的其他节点所接受。
网络中的每一个全节点都会独立地对新区块进行检查,包括但不限于:
- 签名验证:检查每一笔交易的数字签名是否有效,确认是资金所有者本人授权的。
- 防止双重支付:检查交易的“输入”是否引用了之前已经被花费过的UTXO。
- 金额检查:确保交易的输入总金额大于或等于输出总金额(差额即为手续费)。
区块合法性检查:
- PoW验证:检查该区块头的哈希值是否确实小于当前的难度目标。这个验证过程非常快速。
- 时间戳验证:确保区块的时间戳在合理的范围内。
- 区块大小检查:确保区块的大小没有超过协议规定的上限。
- Coinbase交易检查:确保区块中的第一笔交易(Coinbase交易,即矿工给自己的奖励)格式正确,且奖励金额没有超过规定(区块奖励+手续费)。
只有通过了以上所有验证,一个区块才被认为是有效的。当节点沿着这个新区块扩展时,就被认为这个新区块被这个节点被接受。
最长链规则
BTC偶尔会发生两个矿工几乎在同一时间都找到了有效区块的情况,这会导致区块链产生一个临时的分叉 (Fork)。这时,网络中就同时存在了两条都合法的、竞争的链。这时最长链规则规定:
- 定义:“最长”指的不是区块数量最多的链,而是包含最多累积工作量(难度最高) 的那条链。在实践中,这通常就是区块数量最多的那条链。
- 过程:当分叉发生时,节点会暂时保留所有分支。但矿工们会选择在他们收到的第一个有效区块所在的分叉上继续挖矿。由于算力是随机分布的,很快就会有一个分支比另一个分支更先挖出下一个区块,从而变得“更长”。
- 最终一致:一旦某个分支变长,所有诚实的节点和矿工都会遵循最长链规则,放弃较短的分支,并切换到最长的那条链上继续工作。被放弃分支上的交易会重新回到待确认的交易池中。
通过这个机制,网络能够自动地、去中心化地解决分歧,并最终回归到一个单一、一致的区块链状态。
区块奖励 (Block Reward)
区块奖励 (Block Reward) 是在基于工作量证明(Proof-of-Work)或权益证明(Proof-of-Stake)的区块链网络中,对成功创建和验证新区块的参与者(即矿工或验证者)的一种经济激励。它是“成功记账的报酬”。
在像BTC这样的网络中,区块奖励主要由两个部分构成:
1. 新币发行 (Coinbase Reward / Block Subsidy) - 凭空创造的奖励
当一个矿工成功挖出一个新区块时,协议会允许他在该区块的第一笔交易(称为Coinbase交易)中,“凭空”创造出一定数量的、全新的加密货币,并将其发送到自己的地址。
- 目的:
- 货币发行:这是该加密货币(如比特币)进入流通的唯一方式。它是一种预先设定的、去中心化的货币发行机制。
- 核心激励:这是激励矿工投入巨额资金购买硬件、消耗电力来维护网络安全的最主要动力。
- 特点:会递减(减半):
- 在比特币协议中,这部分奖励被设计为大约每四年(或每210,000个区块)减少一半。这个事件被称为“减半” (Halving)。
- 比特币减半历史:
- 2009年起:每个区块奖励 50 BTC
- 2012年减半:每个区块奖励 25 BTC
- 2016年减半:每个区块奖励 12.5 BTC
- 2020年减半:每个区块奖励 6.25 BTC
- 2024年4月减半后:每个区块奖励 3.125 BTC
2. 交易手续费 (Transaction Fees) - 用户支付的服务费
这是区块奖励的第二个组成部分。一个区块内通常包含了很多笔用户发起的交易。用户在发起交易时,可以自愿附加一笔手续费,以激励矿工优先将自己的交易打包进区块。
- 目的:
- 激励打包:当网络拥堵、待确认的交易很多时,矿工会优先选择那些支付了更高手续费的交易进行打包,因为这能让他们获得更多收益。
- 长期安全预算:随着新币发行奖励的不断减半,交易手续费将逐渐成为矿工收入的主要来源。在所有比特币都被挖出后,交易手续费将是维持网络安全的唯一经济激励。
- 特点:市场化波动:
- 手续费的多少不是固定的,而是由市场供需决定的。当网络使用量大、交易需求高时,用户为了让自己的交易尽快被确认,愿意支付更高的手续费,从而导致手续费整体上涨。反之亦然。
一个矿工成功挖出一个区块后,他得到的总奖励是: 总区块奖励 = 新币发行 (Coinbase Reward) + 该区块内所有交易的手续费总和 Total Block Reward = Block Subsidy + Transaction Fees