JSRUN 用代码说话

可编程支付原理

编辑教程

可编程支付原理

比特币的所有交易的信息都被记录在比特币的区块链中,任何用户都可以通过公钥查询到某个交易的输入和输出金额。当某个用户希望花费一个输出时,例如,小明想要把某个公钥地址的输出支付给小红,他就需要使用自己的私钥对这笔交易进行签名,而矿工验证这笔交易的签名是有效的之后,就会把这笔交易打包到区块中,从而使得这笔交易被确认。

但比特币的支付实际上并不是直接支付到对方的地址,而是一个脚本,这个脚本的意思是:谁能够提供另外一个脚本,让这两个脚本能顺利执行通过,谁就能花掉这笔钱:

FROM: UTXO Hash#index
AMOUNT: 0.5 btc
TO: OP_DUP OP_HASH160 <address> OP_EQUALVERIFY OP_CHECKSIG

所以,比特币交易的输出是一个锁定脚本,而下一个交易的输入是一个解锁脚本。必须提供一个解锁脚本,让锁定脚本正确运行,那么该输入有效,就可以花费该输出。

我们以真实的比特币交易为例,某个交易的某个输出脚本是76a914dc...489c88ac这样的二进制数据,注意这里的二进制数据是用十六进制表示的,而花费该输出的某个交易的输入脚本是48304502...14cf740f这样的二进制数据,也是十六进制表示的:

   ┌─────────────────────────────────────────────────────────────────────┐
   │tx:ada3f1f426ad46226fdce0ec8f795dcbd05780fd17f76f5dcf67cfbfd35d54de  │
   ├──────────────────────────────────┬──────────────────────────────────┤
   │                                  │1M6Bzo23yqad8YwzTeRapGXQ76Pb9RRJYJ│──┐
   │                                  ├──────────────────────────────────┤  │
   │                                  │18gJ3jeLdMnr9g3EcbRzXwNssYEN5yFHKE│  │
   │3JXRVxhrk2o9f4w3cQchBLwUeegJBj6BEp├──────────────────────────────────┤  │
   │                                  │1A5Mp8jHcMJEqZUmcsbmtqXfsiGdWYmp6y│  │
   │                                  ├──────────────────────────────────┤  │
   │                                  │3JXRVxhrk2o9f4w3cQchBLwUeegJBj6BEp│  │
   └──────────────────────────────────┴──────────────────────────────────┘  │
┌───────────────────────────────────────────────────────────────────────────┘
│   script: 76a914dc5dc65c7e6cc3c404c6dd79d83b22b2fe9f489c88ac
│
│  ┌─────────────────────────────────────────────────────────────────────┐
│  │tx:55142366a67beda9d3ba9bfbd6166e8e95c4931a2b44e5b44b5685597e4c8774  │
│  ├──────────────────────────────────┬──────────────────────────────────┤
└─>│1M6Bzo23yqad8YwzTeRapGXQ76Pb9RRJYJ│13Kb2ykVGpNTJbxwnrfoyZAwgd4ZpXHv2q│
   └──────────────────────────────────┴──────────────────────────────────┘
    script: 4830450221008ecb5ab06e62a67e320880db70ee8a7020503a055d7c45b7
            3dcc41adf01ea9f602203a0d8f4314342636a6a473fc0b4dd4e49b62be28
            8f0a4d5a23a8f488a768fa9b012103dd8763f8c3db6b77bee743ddafd33c
            969a99cde9278deb441b09ad7c14cf740f

我们先来看锁定脚本,锁定脚本的第一个字节76翻译成比特币脚本的字节码就是OP_DUP,a9翻译成比特币脚本的字节码就是OP_HASH160。14表示这是一个20字节的数据,注意十六进制的14换算成十进制是20,于是我们得到20字节的数据。最后两个字节,88表示字节码OP_EQUALVERIFY,ac表示字节码OP_CHECKSIG,所以整个锁定脚本是:

        OP_DUP 76
    OP_HASH160 a9
          DATA 14 (dc5dc65c...fe9f489c)
OP_EQUALVERIFY 88
   OP_CHECKSIG ac

我们再来看解锁脚本。解锁脚本的第一个字节48表示一个72字节长度的数据,因为十六进制的48换算成十进制是72。接下来的字节21表示一个33字节长度的数据。因此,该解锁脚本实际上只有两个数据。

DATA 48 (30450221...68fa9b01)
DATA 21 (03dd8763...14cf740f)

接下来,我们就需要验证这个交易是否有效。要验证这个交易,首先,我们要把解锁脚本和锁定脚本拼到一块,然后,开始执行这个脚本:

          DATA 48 (30450221...68fa9b01)
          DATA 21 (03dd8763...14cf740f)
        OP_DUP 76
    OP_HASH160 a9
          DATA 14 (dc5dc65c...fe9f489c)
OP_EQUALVERIFY 88
   OP_CHECKSIG ac

比特币脚本是一种基于栈结构的编程语言,所以,我们要先准备一个空栈,用来执行比特币脚本。然后,我们执行第一行代码,由于第一行代码是数据,所以直接把数据压栈:

│                   │
│                   │
│                   │
│                   │
│                   │
│                   │
├───────────────────┤
│30450221...68fa9b01│
└───────────────────┘

紧接着执行第二行代码,第二行代码也是数据,所以直接把数据压栈:

│                   │
│                   │
│                   │
│                   │
├───────────────────┤
│03dd8763...14cf740f│
├───────────────────┤
│30450221...68fa9b01│
└───────────────────┘

接下来执行OP_DUP指令,这条指令会把栈顶的元素复制一份,因此,我们现在的栈里面一共有3份数据:

│                   │
│                   │
├───────────────────┤
│03dd8763...14cf740f│
├───────────────────┤
│03dd8763...14cf740f│
├───────────────────┤
│30450221...68fa9b01│
└───────────────────┘

然后,执行OP_HASH160指令,这条指令会计算栈顶数据的hash160,也就是先计算SHA-256,再计算RipeMD160。

对十六进制数据03dd8763f8c3db6b77bee743ddafd33c969a99cde9278deb441b09ad7c14cf740f计算hash160后得到结果dc5dc65c7e6cc3c404c6dd79d83b22b2fe9f489c,然后用结果替换栈顶数据:

│                   │
│                   │
├───────────────────┤
│dc5dc65c...fe9f489c│
├───────────────────┤
│03dd8763...14cf740f│
├───────────────────┤
│30450221...68fa9b01│
└───────────────────┘

接下来的指令是一条数据,所以直接压栈:

├───────────────────┤
│dc5dc65c...fe9f489c│
├───────────────────┤
│dc5dc65c...fe9f489c│
├───────────────────┤
│03dd8763...14cf740f│
├───────────────────┤
│30450221...68fa9b01│
└───────────────────┘

然后,执行OP_EQUALVERIFY指令,它比较栈顶两份数据是否相同,如果相同,则验证通过,脚本将继续执行,如果不同,则验证失败,整个脚本就执行失败了。在这个脚本中,栈顶的两个元素是相同的,所以验证通过,脚本将继续执行:

│                   │
│                   │
│                   │
│                   │
├───────────────────┤
│03dd8763...14cf740f│
├───────────────────┤
│30450221...68fa9b01│
└───────────────────┘

最后,执行OP_CHECKSIG指令,它使用栈顶的两份数据,第一份数据被看作公钥,第二份数据被看作签名,这条指令就是用公钥来验证签名是否有效。根据验证结果,成功存入1,失败存入0:

│                   │
│                   │
│                   │
│                   │
│                   │
│                   │
├───────────────────┤
│1                  │
└───────────────────┘

最后,当整个脚本执行结束后,检查栈顶元素是否为0,如果不为0,那么整个脚本就执行成功,这笔交易就被验证为有效的。

上述代码执行过程非常简单,因为比特币的脚本不含条件判断、循环等复杂结构。上述脚本就是对输入的两个数据视作签名和公钥,然后先验证公钥哈希是否与地址相同,再根据公钥验证签名,这种标准脚本称之为P2PKH(Pay to Public Key Hash)脚本。

输出

当小明给小红支付一笔比特币时,实际上小明创建了一个锁定脚本,该锁定脚本中引入了小红的地址。要想通过解锁脚本花费该输出,只有持有对应私钥的小红才能创建正确的解锁脚本(因为解锁脚本包含的签名只有小红的私钥才能创建),因此,小红事实上拥有了花费该输出的权利。

使用钱包软件创建的交易都是标准的支付脚本,但是,比特币的交易本质是成功执行解锁脚本和锁定脚本,所以,可以编写各种符合条件的脚本。比如,有人创建了一个交易,它的锁定脚本像这样:

OP_HASH256
      DATA 6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000
  OP_EQUAL

这有点像一个数学谜题。它的意思是说,谁能够提供一个数据,它的hash256等于6fe28c0a...,谁就可以花费这笔输出。所以,解锁脚本实际上只需要提供一个正确的数据,就可以花费这笔输出。点这里查看谁花费了该输出。

比特币的脚本通过不同的指令还可以实现更灵活的功能。例如,多重签名可以让一笔交易只有在多数人同意的情况下才能够进行。最常见的多重签名脚本可以提供3个签名,只要任意两个签名被验证成功,这笔交易就可以成功。

FROM: UTXO Hash#index
AMOUNT: 10.5 btc
TO: P2SH: OP_2 pk1 pk2 pk3 OP_3 OP_CHECKMULTISIG

也就是说,3个人中,只要任意两个人同意用他们的私钥提供签名,就可以完成交易。这种方式也可以一定程度上防止丢失私钥的风险。3个人中如果只有一个人丢失了私钥,仍然可以保证这笔输出是可以被花费的。

支付的本质

从比特币支付的脚本可以看出,比特币支付的本质是由程序触发的数字资产转移。这种支付方式无需信任中介的参与,可以在零信任的基础上完成数字资产的交易,这也是为什么数字货币又被称为可编程的货币。

由此催生出了智能合约:当一个预先编好的条件被触发时,智能合约可以自动执行相应的程序,自动完成数字资产的转移。保险、贷款等金融活动在将来都可以以智能合约的形式执行。智能合约以程序来替代传统的纸质文件条款,并由计算机强制执行,将具有更高的更低的信任成本和运营成本。

JSRUN闪电教程系统是国内最先开创的教程维护系统, 所有工程师都可以参与共同维护的闪电教程,让知识的积累变得统一完整、自成体系。 大家可以一起参与进共编,让零散的知识点帮助更多的人。
X
支付宝
9.99
无法付款,请点击这里
金额: 0
备注:
转账时请填写正确的金额和备注信息,到账由人工处理,可能需要较长时间
如有疑问请联系QQ:565830900
正在生成二维码, 此过程可能需要15秒钟