锁进微型谜题盒的币
想象一个有巧思的行李寄存柜:它没有固定的钥匙,而是在柜门上印着一道小小的谜题。谁能答出谜题,谁就能打开它。大多数谜题都很简单——*「证明你拥有配对的钥匙」*——但造柜人原则上也能印上更古怪的题目。
比特币几乎就是这样运作的。你持有的每一枚币,实际上是链上一个未花费输出,每个输出都附带一个小程序——锁定脚本——上面写着那道谜题。要花掉它,你得提供一个解锁脚本,也就是你的答案。网络把这两段脚本拼在一起运行,如果最终给出「通过」,这枚币就归你支配。书写这些谜题所用的语言,就叫 Script。
Script 如何运行:一摞盘子
Script 是一门基于栈的语言,而栈不过是一摞盘子:你只能往最上面加一个盘子(压入 push),或把最上面那个拿走(弹出 pop)。脚本就是一串从左到右读取的指令。有些指令负责压入数据——一个数字、一段签名、一把密钥;另一些是操作码(opcode),会弹出一两个盘子,做点运算,再把结果压回去。
要校验一次花费,节点先摆上你的解锁脚本,再接上锁定脚本,然后整段一起运行。最后的判定规则简单得令人愉快:如果栈顶的盘子是「真」(一个非零值),币就解锁;如果栈最终为空、为假,或脚本撞上了被禁止的动作,这次花费就被拒绝。
unlocking: <push 3> <push 4> locking: OP_ADD <push 7> OP_EQUAL stack walk-through (top is rightmost): push 3 -> [ 3 ] push 4 -> [ 3, 4 ] OP_ADD -> [ 7 ] # pop 3 and 4, push 3+4 push 7 -> [ 7, 7 ] OP_EQUAL -> [ true ] # pop both, equal? push true Top plate is true -> coin unlocks.
日常谜题:付款给公钥哈希
几乎所有真实的币都使用一种标准谜题,付款给公钥哈希(P2PKH)。用大白话说就是:*「要花掉我,请出示一把哈希后等于这个地址的公钥,外加一段由其配对私钥签出的有效签名。」* 它把币绑定在唯一的所有者身上,而且直到花费那一刻才暴露公钥——这在隐私与安全上都是漂亮的一手。
locking (on the coin): OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG unlocking (you provide): <signature> <pubKey> idea: 1. duplicate your pubKey, hash it 2. EQUALVERIFY: must match the address baked in 3. CHECKSIG: signature must be valid for that key all pass -> true -> spend allowed
请留意这道谜题做的事其实少得可怜:复制、哈希、比较、验证一段签名。没有循环,没有「如果价格高于 X」,也不会向互联网发起调用。这种简约并不是缺了功能——它本身就是核心用意,下一节会解释。
刻意做小:没有循环,没有意外
Script 是刻意设计成非图灵完备的。尤其是它没有循环、不能向后跳转——一段脚本总是笔直、有限地走完,然后停下。这听起来像缺点,却换来两条无价的保证。其一,每个节点都知道脚本会很快结束;没法写出一段永远运行、把网络卡死的脚本。其二,校验一笔交易的成本在运行前就是可预测的。
即便如此,Script 也不止于「单一所有者」的谜题。一种流行的模式是多重签名(multisig)——「N 把密钥里必须有 M 把签名」。一个共享的企业钱包可以这样锁定资金:需要 3 选 2 的公司董事才能放款,从而消除任何单点故障。这道谜题只是收集几段签名,再数一数其中有效的有几段。
2-of-3 multisig locking script: OP_2 <pubKey_A> <pubKey_B> <pubKey_C> OP_3 OP_CHECKMULTISIG unlocking (any two valid signatures): OP_0 <sig_from_A> <sig_from_C> meaning: "release the coin only if at least 2 of these 3 named keys each sign." (the leading OP_0 is a dummy: OP_CHECKMULTISIG has an old off-by-one bug that pops one extra item.)
天花板——以及通往以太坊的桥
多重签名,再加上少数几种时间锁和哈希锁的小花招,差不多就是纯 Script 所能表达的极限了。你无法写出「只有当某队赢了比赛才付款」,或「每月把这笔房租分给十位租客」,或「运营一个小型借贷市场」。Script 能用巧妙的锁守住一枚币,却撑不起一个持续存在、带状态、能持有资金并随时间作出反应的程序。
正是这道天花板,催生了下一个大想法。既然一枚币能携带一个*小*程序,为什么不能携带一个完整的程序——带循环、带内存,能自由表达任何规则呢?这个问题,给了我们智能合约,以及围绕它构建的各种网络。比特币选择了一把紧致、极度安全的锁;下一条学习线则选择了纯粹的可编程性,并用另一套方式去管理随之而来的新风险。