8.交易脚本
8.1 核心概念
-
脚本语言:
- 基于栈(Stack) 的语言。所有操作(指令)都是对栈顶数据进行操作(压入、弹出、计算、验证)。
- 指令通常以
OP_开头(如OP_CHECKSIG)。 - 不支持循环,是图灵不完备的(出于安全性和确定性考虑)。
- 密码学操作(哈希、签名验证)是其核心功能。
-
脚本执行:
- 交易的解锁脚本(Input Script / ScriptSig) 和对应 UTXO 的锁定脚本(Output Script / ScriptPubKey) 会被拼接在一起执行。
- 出于安全考虑,它们确实是分别执行的:先执行解锁脚本(将数据压入栈),再执行锁定脚本(对栈上数据进行验证)。这防止了解锁脚本中的恶意操作直接影响锁定脚本的执行逻辑。
- 执行结果:栈顶最终结果为
True(非零值,通常是1) 表示验证成功,允许花费该 UTXO;结果为False(零) 表示验证失败。
-
常见脚本类型:
-
1.
P2PK(Pay to Public Key - 早期/简单):- 锁定脚本 (Output):
<Public Key> OP_CHECKSIG - 解锁脚本 (Input):
<Signature> - 执行过程:
- 输入脚本执行:压入签名
Sig。 - 输出脚本执行:压入公钥
PubKey,然后执行OP_CHECKSIG。 OP_CHECKSIG弹出栈顶的两个元素 (Sig和PubKey),用公钥验证签名是否对该交易有效。验证成功压入1(True),失败压入0(False)。
- 输入脚本执行:压入签名
- 笔记中的
sig pubkey checksig指的就是这种基本模式。
- 锁定脚本 (Output):
-
2.
P2PKH(Pay to Public Key Hash - 最常用):- 锁定脚本 (Output):
OP_DUP OP_HASH160 <Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG - 解锁脚本 (Input):
<Signature> <Public Key> - 执行过程 (拼接后):
- 压入签名
Sig。 - 压入公钥
PubKey。 OP_DUP: 复制栈顶公钥 (现在栈:Sig, PubKey, PubKey)。OP_HASH160: 弹出栈顶公钥,计算其 RIPEMD160(SHA256) 哈希值并压入 (现在栈:Sig, PubKey, PubKeyHash_Calculated)。- 压入锁定脚本中提供的公钥哈希
<Public Key Hash>(现在栈:Sig, PubKey, PubKeyHash_Calculated, PubKeyHash_Provided)。 OP_EQUALVERIFY: 弹出栈顶两个元素 (PubKeyHash_Calculated和PubKeyHash_Provided),比较它们是否相等。如果不相等,脚本立即失败终止。 如果相等,继续执行 (现在栈:Sig, PubKey)。OP_CHECKSIG: 弹出栈顶两个元素 (Sig和PubKey),验证签名。验证成功压入1(True),失败压入0(False)。
- 压入签名
- 笔记中流程描述正确,术语
PUSHDATA是隐含的(<Signature>,<Public Key>,<Public Key Hash>这些本身就是压入数据的操作)。EQUALVERIFY是关键的安全步骤。
- 锁定脚本 (Output):
-
3.
P2SH(Pay to Script Hash - 用于复杂脚本/多重签名):- 核心思想: 将复杂脚本(赎回脚本
RedeemScript)的哈希值放在锁定脚本中。花费时提供原始脚本和满足它的参数。 - 锁定脚本 (Output):
OP_HASH160 <RedeemScript Hash> OP_EQUAL(非常简单,只存哈希) - 解锁脚本 (Input):
<Sig1> [Sig2] ... <RedeemScript>(提供满足RedeemScript所需的签名和RedeemScript本身) - 执行过程 (两阶段验证):
- 阶段 1 (验证脚本哈希匹配):
- 输入脚本执行:依次压入提供的签名等参数,最后压入
RedeemScript。 - 输出脚本执行:
OP_HASH160(弹出栈顶的RedeemScript,计算其哈希值并压入)。 - 压入锁定脚本中的
<RedeemScript Hash>。 OP_EQUAL:比较计算出的哈希值和提供的哈希值是否相等。结果 (1或0) 压入栈顶。如果此时栈顶是0,脚本失败。 (OP_EQUAL只压入结果,不立即终止,但后续步骤依赖它为真)
- 输入脚本执行:依次压入提供的签名等参数,最后压入
- 阶段 2 (验证赎回脚本):
- 如果阶段1成功(栈顶是
1),反序列化栈中之前压入的RedeemScript,将其内容作为新的脚本指令序列执行。此时栈上还留有之前压入的签名等参数。 - 执行
RedeemScript。这个脚本通常包含实际的验证逻辑(如m-of-n多重签名OP_CHECKMULTISIG)。 RedeemScript执行的结果决定最终验证是否通过。
- 如果阶段1成功(栈顶是
- 阶段 1 (验证脚本哈希匹配):
- 优点:
- 发送方只需知道一个简单的哈希地址,无需关心复杂的接收条件。
- 复杂逻辑(如多重签名)从锁定脚本移到了赎回脚本,简化了标准交易。
- 提供了一定的冗余:多重签名允许多个私钥持有者授权交易(m-of-n),即使个别私钥丢失,只要满足最小签名数 m 即可。
OP_CHECKMULTISIG(多重签名验证):- 语法:
<m> <PubKey1> <PubKey2> ... <PubKeyn> <n> OP_CHECKMULTISIG - 执行:验证栈上提供的签名数量是否至少为
m,并且这些签名与提供的公钥列表中的m个公钥有效对应(顺序需匹配)。 - 笔记中的
checkmultisig指的就是这个操作码。
- 语法:
- 注意: 当前交易的输入脚本(提供签名和
RedeemScript)是和币来源交易(创建该 UTXO 的交易)的输出脚本(包含哈希承诺)进行拼接验证的。
- 核心思想: 将复杂脚本(赎回脚本
-
4.
OP_RETURN/ Proof of Burn (销毁证明):- 锁定脚本 (Output):
OP_RETURN <Optional Data> - 特点:
OP_RETURN指令执行后会立即标记脚本为无效(返回 False)。- 发送到这个地址的比特币永远无法被花费,即被销毁。
- 主要用途:
- 销毁一定数量的 Bitcoin: 有时用于减少流通量或特定协议要求。
- 添加数据到区块链 (Digital Commitment):
<Optional Data>部分可以存储少量信息(如哈希值、时间戳、文本),作为存在性证明或锚定其他系统。这是最常见的用途。 - 创建 Altcoin (替代币): 早期一些 Altcoin 通过销毁 BTC 来分配新币(现已不常见)。
- 笔记中
return命令之后都会直接报错描述准确。digital commitment是其核心应用之一。
- 锁定脚本 (Output):
-
8.2 其它
Coinbase交易: 每个区块的第一个交易,是矿工的奖励。这个交易的输入(scriptSig)有特殊规则,可以由矿工自由写入一些数据(通常包括 Extra Nonce 和区块高度),而普通交易的输入是指向之前某个 UTXO 的输出。其输出脚本(锁定脚本)决定了奖励发送给哪个地址。- 零知识证明: 比特币脚本本身不直接支持通用的零知识证明(如 zk-SNARKs)。像
OP_CHECKSIG这样的操作码验证签名时,虽然签名本身不直接暴露私钥,但这是一种标准的公钥密码学验证,不是零知识证明。比特币生态中实现强隐私通常需要额外的协议层(如 CoinJoin)或侧链/二层解决方案(如使用 zk-rollups)。核心脚本语言的设计更注重简洁和安全。
- 理解栈操作: 脚本执行如何通过压栈、弹栈、操作码处理数据。
- 区分 ScriptSig 和 ScriptPubKey: 它们的作用、拼接方式和分阶段执行的原因(安全)。
- 掌握 P2PKH 流程:
DUP,HASH160,EQUALVERIFY,CHECKSIG每一步的目的和栈的变化。 - 理解 P2SH 原理: 两阶段验证(哈希匹配 + 赎回脚本执行)、目的(简化复杂脚本)、应用(多重签名)。
- 理解多重签名 (
OP_CHECKMULTISIG): m-of-n 的含义和优势(冗余)。 - 理解
OP_RETURN: 作用(创建不可花费输出、存储数据)、结果(脚本总是失败)。 - 明确
Coinbase特殊性: 矿工奖励来源,输入脚本可自定义。 - 知晓比特币脚本的局限性: 无循环、图灵不完备、不支持原生零知识证明。