美文网首页区块链研习社程序员
零基础搞懂比特币的交易创建

零基础搞懂比特币的交易创建

作者: 赵小峰的思想迭代器 | 来源:发表于2018-05-06 21:39 被阅读25次

为了让你了解比特币交易的构造,我提供了以下最小必要知识:

  • 比特币交易的组成元素

  • 交易脚本中的构成元素

比特币交易的组成元素

一个普通的交易主要包含输入输出两个元素(暂时不关心版本号和锁定时间这两个元素,它们通常分别设置成1和0)。

  • 输入(vin):指定要花费的余额,并且将该余额解锁。

  • 输出(vout):其作用是把已解锁的余额重新锁定起来,并且指定某个比特币地址才能解锁该余额。

以下就是一条交易(先不用管详细内容,后面会慢慢介绍)。

{
  "version": 1,
  "locktime": 0,
  "vin": [
    {
      "txid":"7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
      "vout": 0,
      "scriptSig": "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
      "sequence": 4294967295
    }
 ],
  "vout": [
    {
      "value": 0.01500000,
      "scriptPubKey": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
    },
    {
      "value": 0.08450000,
      "scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
    }
  ]
}

如果用户B转账给用户C,那么她会构建这样一条交易:输入里面把她要花费的余额解锁掉,再在输出里面指定C才能解锁该余额。

那么问题来了,B的可花费的余额是哪里来的?假设B的比特币都是A转给她的,那么B的可花费的余额就是:A转给B那笔交易的输出。A转给B的那笔交易的输出中指定:只有B才能解锁这笔余额。

所以输入由以下元素组成:

  • 选择某条交易中的某个输出

  • 提供解锁脚本,将该笔资金解锁

那么问题又来了,A的钱又是哪里来的???实际上不断追溯源头的话,最终大家的比特币都来自于一种叫做币基交易(coinbase)的特殊交易,币基交易是没有输入的,而币基交易是由挖到矿的矿工生成的,所以比特币就是矿工挖出来的。

那么如果我有0.5个比特币,我总不能把0.5个比特币全都转给你吧,我得给自己留点。一条交易中是可以有多个输出的,我可以把0.12个比特币转给A,0.35个比特币转给B,然后把0.02个比特币转给我自己。

那么问题又又来了,0.12 + 0.35 + 0.02 = 0.49,为什么不是0.5。因为输出的金额减去输入的金额,就是给矿工的矿工费,这样他们会尽快给这笔交易打包,矿工费越高,打包地越快。通常情况下,并不需要0.01那么高的矿工费,可以进入https://bitcoinfees.earn.com/进行查询当前时间下交易所需要的矿工费。

在以上的交易中有三笔输出,这就是三笔“未花费的交易输出”(unspent transaction outputs),即UTXO。

输出由以下元素组成:

  1. 指定这笔输出的金额

  2. 提供锁定脚本,把这笔金额锁住,指定谁才能把它解锁

另外,在一笔交易中也可以有多个输入,这样就可以把所有“未花费的交易输出”(UTXO)集中花费掉。

交易脚本中的构成元素

从上一节我们知道,有用来解锁资金的解锁脚本,以及锁定资金的锁定脚本,解锁脚本是在"输入"中,锁定脚本是在"输出"中。

那么这些脚本长什么样呢?比特币交易脚本语言是一种逆波兰表达式的基于堆栈的执行语言,在此不对这种堆栈执行语言做更多解释。

在介绍解锁、锁定脚本之前,先介绍一下比特币的私钥、公钥、比特币地址之间的关系。


关于比特币公钥私钥的特性,只需要知道这两点:

  1. 私钥经过椭圆算法之后生成公钥,公钥经过哈希算法之后生成比特币地址(也就是公钥哈希)。这个过程是不可逆的,也就是说公钥不能生成私钥,比特币地址也不能反推到公钥。

  2. 一段文本经过私钥加密之后只能由公钥进行解密,而由公钥加密之后的文本只能由私钥解密,这就是非对称加密算法。

输出中的一种典型的锁定脚本如下:

OP_DUP OP_HASH160 <Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG

其中需要注意的是,<Public Key Hash>是公钥哈希也就是比特币地址,锁定脚本中指定了拥有该比特币地址的人才能解锁该脚本。

输入中的一种典型的的解锁脚本如下:

<Signature> <Public Key>

解锁脚本提供了<Signature>签名以及<Public Key>公钥,该签名是私钥将交易加密后产生的。

当验证脚本的时候,需要把两个脚本组合起来如下:

<Signature> <Public Key> OP_DUP OP_HASH160 <Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG

以上的运行规则类似逆波兰表达式的堆栈脚本,流程如下:

  1. 首先验证的是解锁脚本提供的公钥,在进行HASH160的哈希运算之后,确定是否和锁定脚本中提供的比特币地址(公钥哈希)一致。

  2. 然后验证的是解锁脚本提供的签名,验证节点会使用公钥对这个签名进行解密,并确认解密后的文本是否正确。

以上最关键的一点就是使用公钥将签名进行解密,这让该比特币的拥有者在不透露私钥的情况证明了所有权,只需要使用私钥生成签名即可。那么私钥加密的文本是什么呢?又或者换个问法,公钥把签名解密后的文本又是什么呢?

此处再提供两点信息:

  1. 以上的验证过程是比特币的全节点收到一条交易B的时候,根据这条交易B中的输入去查找相应的交易A,再将交易A中的输出锁定脚本和交易B中的输入解锁脚本,两者结合起来验证。

  2. 而这条交易B是由某个用户的比特币钱包生成的,以上说的签名是放在交易B中的解锁脚本中,而签名就是私钥基于交易B这个文本加密产生的。

有没有发现哪里不对?从上面我们可以提取出以下信息

  • 签名是放在交易B中的。

  • 签名是使用私钥将交易B加密后的产物。

问题来了,到底是交易B先生成还是签名先生成,这是先有鸡还是先有蛋的问题。

那么为大家解答一下,签名生成的步骤:

  1. 把交易B中的解锁脚本字段填充成相应交易A的输出中的锁定脚本(并改变相应的长度)。

  2. 在第一步产生的文本加上小端序4字节的签名类型0x01(灰色部分),并计算两次SHA256。

  3. 再把第二步中计算完的SHA256的文本进行私钥加密,最后得到签名。

从以上步骤中可以看出,因为签名是在解锁脚本中的,所以当利用交易B生成签名的时候,解锁脚本字段暂时是被交易A的输出中的锁定脚本所填充的,签名生成之后,再将签名放在解锁脚本中,之后把真正的解锁脚本放在交易B的解锁脚本字段中,这样交易B就完整地生成了!!!

如下图中的sigScript就是解锁脚本,pkScript就是锁定脚本。


参考资料:
https://github.com/tianmingyun/MasterBitcoin2CN/blob/master/ch06.md
http://www.infoq.com/cn/articles/deep-understanding-of-bitcoin-transaction-script


【原创·转载请声明】本文由【登峰计划】鼎力支持,加入登峰计划收益翻10倍
如需加群,加我微信zbffff,备注信息:登峰计划。

相关文章

网友评论

    本文标题:零基础搞懂比特币的交易创建

    本文链接:https://www.haomeiwen.com/subject/mkfprftx.html