zoukankan      html  css  js  c++  java
  • 比特币交易流程:交易生成、验证、打包、发布

    在比特币网络中,一笔交易是如何进行的?本文是笔者的理解,若有错误,欢迎批评指出 QQ:921658495

     

    A要转给B十个ETH,首先A需要有10ETH,其次A需要有B的公钥HASH

    为什么A需要B的公钥hash?这个问题我们待会再回答,我们先看一下转账是怎么回事.

    在比特币系统中,是没有账户的概念的,余额没有存在账户中,而是一个叫UTXO的数据结构,

                UTXO的结构

      一个地址可以有多个UTXO,每个UTXO上有字段value,可以理解为每个UTXO上都有一个余额,而这个余额就是这个UTXO里有多少钱。

    转帐前,我要先验证A确实有10ETH(矿工来验证),如何验证呢?

    UTXO集合中是所有未花费输出,找到集合中addrA的地址的UTXO,然后将所有value加起来,就是A的总钱数。

    转账时UTXO的变化?

      比如说A3张银行卡(3UTXO,每张卡里有50ETH(每个UTXO中的value50)。而A转给B时,并不是将一张银行卡中钱转出到B的银行卡,而是将A的这张卡销毁(UTXOspent字段设为TRUE,表示已花),然后再生成2个银行卡(一个是BUTXO,接受A转给他的10ETH;一个是AUTXO,接受找零的40ETH)。

    为什么还需要生成一个AUTXO,直接将A之前的UTXO中减去10不行吗?

      比特币系统中花费UTXO时,必须一次性花完,花不完需要有一个找零地址,如果没有找零地址,找零的这部分钱就会作为交易费支付该矿工。下面第二个A就是一个找零地址

    回到之前的问题,为什么AB转账需要B的公钥hash呢?

      刚才说了,转账时,生成目标地址的UTXO,花费转账方的UTXO。那么A如何花费它的UTXO时,是不是需要一些验证呢,如果没有验证,任何人都跑来花费AUTXO

    那么,如何验证A花费的是属于它的UTXO呢?(涉及到P2PKH

      这里涉及到锁定脚本和解锁脚本,每个UTXO在生成时,都会用这个UTXO的拥有者A的公钥(实际是公钥HASH)进行锁定,比如说A在花费它的UTXO时,A需要用自己的公钥明文和签名进行解锁。解锁过程分两步:1、解锁脚本中A的公钥明文经过HASH160加密后,是否与锁定脚本中A的公钥HASH相等 2、公钥验证通过后,公钥验证解锁脚本中A的签名。如果能解锁成功,说明这个UTXO确实是A的,那么A就可以花这个UTXO了。

    到这里A转账给B时为什么需要B的公钥HASH,已经解决,那么问题又来了:A如何获取B的公钥HASH

      我们都知道每笔交易打包时都需要在链上广播,而广播时不就知道B的公钥明文或者hash了吗,确实!但是如果B是新生成的地址,从未进行过任何交易,也从未进行过任何广播,那么A怎样才能知道B的公钥HASH呢?B的地址就是B的公钥HASH的编码,地址和公钥hash是可以相互转换。我们可以看一下地址是如何生成的:

    1、随机生成私钥

    2、进行SHA256和RIPEMD160两次加密(不可逆)

    3、截取前20BYTES得到公钥HASH

    4、公钥经过BASE58编码得到地址(类似BASE64,可逆的)

    我们看一下一笔交易中的代码体现:

    这里的两个输出:实际上是生成了两个UTXO,上面体现的好像不是很明显,下图是在比特币浏览器上截的图

    不知道大家有没有注意到,上面验证A是否可以花费这个UTXO时,验证了解锁脚本中的签名,问签名的内容是什么?

      签名的内容是这笔交易的内容,ScriptSig是解锁脚本,签名+公钥+指令应该放到这个ScriptSig里面,但是这个键本身就属于交易的一部分,那么岂不是矛盾了吗?看到一个大佬的博客后恍然大悟,签名的内容确实是这笔交易,但签名时把ScriptSig替换成B(接收方)的锁定脚本的内容,然后再对整个交易进行签名,最后再把签名+公钥+指令编码后放在ScriptSig

     

                  签名前的交易

              Scriptsig进行填充,对填充后的交易签名

                签名后,替换到ScriptSig

    交易部分基本结束,现在我们知道一笔交易是如何让验证,如何签名,UTXO是如何变化的了。

    上面篇幅已经讲了交易生成,接下来将交易打包到区块。

    注意,这里不是两个独立的概念,下图中粗略展示了交易和区块的关系

    注意:区块链的是不可篡改的分布式账本,他的目的是为了记账,也就是把交易打包到区块链中。

    打包过程:

    A要转给B十个ETH,这笔交易被广播到比特币网络上,所有矿工节点接收到后,先对这笔交易进行合法性验证,也就是上文中的签名,脚本等。

    验证通过的话,将这笔交易放在矿工本地的chainstate中(可以理解为临时存放区),然后矿工从chainstate中挑选出一些交易,优先挑选交易费高的,但不能太多,区块容量不能超出1M。

    然后将这些交易构造成merkel tree,计算出这颗tree的root hash,再加上version、previous_hash(前一个区块头Hash)、target(目标阈值)、timestamp(时间戳)还有nonce(随机数),上面这6个值一起进行HASH运算,要求得到的运算出的HASH<=target,如果不满足,变换nonce,继续进行HASH运算,这个过程就成为挖矿。

    直到满足HASH<=target,说明找到了满足要求的nonce,也就是挖到矿了。

    然后矿工节点将上面这些数据按照区块的数据结构打包成一个区块,广播至其他节点进行验证,其他节点验证时主要验证块结构、是否满足挖矿难度、时间戳、merkel tree root hash、块大小、coinbase(一个区块只能有一个)。

    如果验证通过,则可以发布到区块链上。

     

      

     

     

  • 相关阅读:
    2.pt-table-checksum工具
    Mysql8.0新特性01
    12.redis 之阅读大佬文章随笔
    4.Mysql之Mysqldump命令
    5. 关于高负载服务器Kernel的TCP参数优化
    Mysql Oracle 备份表数据、批量删除表数据
    Mysql limit用法
    Java 字符串数组转字符串
    Layui 自定义年份下拉框并且可输入
    Mysql 生成UUID
  • 原文地址:https://www.cnblogs.com/kunspace/p/13260932.html
Copyright © 2011-2022 走看看