区块链中,交易被如何打包进区块

大部分材料都详细分析了挖矿过程,介绍了区块是如何产生的。然而,区块的产生并不是区块链的最终目的,保存交易信息才是区块链的最终目的。所以,更重要的一点是要理解,交易信息是如何被打包进区块链的。

输入和输出

一个交易在系统里被输入和输出表示。输入是指这笔交易所要进行转移的币来自之前的哪些输出。输出是指这些币将会被发送给哪些地址。在区块链上记账,不是告诉你一个账号现在有多少钱,而是告诉你这个账号当前得到了哪些输出。比如一个地址xsw0923sdfew2389dsfw它的相关记录里面,有A、B、C三个输出的目标地址是它,那么它实际上的余额就是这三个输出的金额的总和。

但是现在这个地址的用户要转账了,转账过程不是直接从总和数字中取出一部分进行转移,而是分别从A、B、C三个输出中取出部分或全部,加起来为想要转移的总和的币,进行转移。这个“取出”过程中,A、B、C就变成了输入,转账目标记录才是这次交易的输出。

这样的设计,保证了区块链中的钱从哪里来,到哪里去,一清二楚,绝不含糊。跟会计做账一样,花一笔钱,不单单要记录它花到哪里去了,还要记录这笔钱是从哪里来的,整个资金链是可追溯的,这也保证了交易不可伪造,资金既不会凭空消失,也不会无中生有。

hash

将交易加入到区块里面需要涉及三个hash,一个是交易本身的hash,另一个是当前这个区块所有交易的merkle hash root,还有一个就是区块hash。

上面已经说过输入与输出了,一个交易可能包含多个输入输出,通过将这些输入输出信息进行排列并进行hash运算,就得到一个交易的唯一hash值。

一个区块里面包含了多个交易,包括挖矿奖励交易,这些交易都被通过一个merkle运算,得到一个hash root所包含,对于merkle可以阅读《区块链如何运用merkle tree验证交易真实性》了解。

区块都hash运算里面,merkle hash root作为一个参数,因此,所有交易的信息都体现在了一个区块的hash里面。

挖矿

挖矿过程就是计算上述区块hash的过程,几乎所有的机器都可以挖矿成功。关键在于谁先挖到矿,因为当一台机器挖矿成功就向网络广播,其他挖矿在对这个hash进行校验之后,就停止自己的挖矿,开始基于这个区块挖新的矿。而每一个被挖到区块中记录的第一笔交易是给挖到这个区块的矿工自己的奖励金,所以抢到第一个挖矿成功名额对于矿工来说至关重要。

前面说过,计算区块hash过程里面,会以区块包含的交易的merkle hash root作为计算的一个参数,因此,挖矿时,矿工会事先从自己本地的交易信息里面提炼出merkle hash root,也就是说,在挖矿之前,对于当前这个矿工来说,新区块会包含哪些交易就已经确定好了的。关于这个过程,可以阅读《Merkle Tree》。

打包交易记录

挖矿成功之后,矿工需要将完整的区块向网络广播,这个时候,这个区块里面就打包了所有上述对应的交易。

现在有三个问题:

  1. 在打包开始之前,这些交易记录是以什么方式存在于网络?
  2. 打包是否会把所有交易记录打包进区块?怎么可能保证所有交易都不被遗漏?
  3. 如何防止矿工伪造交易?将伪造的交易打包进区块?

手续费

这里需要知道另外一个概念,即“手续费”。手续费是发起交易的节点决定给的,和小费性质一样。比如A打算转给B0.5个BTC,A手上有一个完整的(来自一个输入)BTC,这时A将这1BTC作为输入,输出包含两条,一条是给B0.5BTC,另一条是给自己0.49BTC(这个过程叫“找零”)。那么这个交易中就有0.01BTC是消失了,消失了的BTC将作为小费奖赏给矿工。

现在我们把自己的角色转换为矿工,当我们从自己的内存中收集所有交易,准备打包区块时,发现这里有一条交易有0.01BTC的小费,于是我把它作为本次打包优先考虑的交易记录。由于每个区块的大小限制在1M左右,所有我只选了那些给小费的交易打包进这次区块。而那些未给交易费的交易,在优先考虑完这些有交易费的交易之后,我才会考虑把它们加进来。

这也就是为什么有些交易被确认很快,有些交易被确认很慢。

确认

“确认”这个概念也要解释一下,一个区块产生之后,它不是立即可信的,网络上的节点总是相信最长的区块链,当一条交易记录被打包进一个区块之后,就有了一个确认,而这个区块所在的链后面被再加入一个区块,就是第二个确认,如此下去,一个交易有了6个确认,我们就认为这个交易已经确定了,会被永远记录在区块链中。为什么是6个确认呢?因为每一个确认就是一个挖矿过程,都需要提供非常严格的计算,因此,这6个区块被同一个矿工创建的可能性微乎其微(可以说是不可能),因此矿工伪造交易也基本不可能。

由于比特币的区块平均产生时间是10分钟,所以一个交易要1小时左右才能保证成功(最快),不过也不是所有的系统都这样认为,有些网站在接受比特币支付时,认为4个确认就可以给客户发货了。如果不幸这个交易在创建的时候,没有被打包进最近的那个区块,那就要延迟10分钟,如此下去,如果后面过了好几个区块,交易都没有被打包进区块链,那就悲剧了。

广播交易

不过也不用着急,比特币系统中只留给了这种优先级高的交易50k的存储空间,即使你没有给交易费,也可能在24小时内被打包进区块。不过也不一定,有些交易可能永远都进不了区块,因为矿工是从自己都内存中获取自己暂存的交易信息,一旦这些内存被释放,那么这些交易信息就会被清空。为了解决这个问题,比特币钱包需要不断对自己发起的交易进行检查,如果发现没有被打包进最新的区块,就要对网络广播,这样,这个交易就会在网络里不断被提起,矿工又可以把这笔交易写进自己的内存里暂时放着,等到下次打包区块时,选择是否把它打包进去。

小结

本文讲解了对于一个交易而言,“创建(输入输出)-广播-挖矿-打包-确认”的整个过程,读完你应该可以理解交易是怎么被打包进区块的了。

2018-03-07 8043

为价值买单

本文价值80.43RMB
已有9条评论
  1. super 2018-09-07 17:08

    首先感谢博主分享,目前我大概了解了旷工的工作包括了挖矿产生区块以及打包交易,我有几个问题有些疑惑想请教下:
    我们在imToken这种钱包里面发起一笔交易,我们通常会在APP里面看到,状态先是等待打包,然后变成打包中,然后就有节点开始确认;
    我想请教下钱包发起转账是,是广播给了所有的旷工还是节点呢?假设广播给了所有的旷工,旷工在收到交易请求后,先放在内存里面,等到挖出区块后,再把交易信息打包到区块里面?是这样一个过程吗?打包剩余的交易是不是也要同步广播给其他的旷工?

    • 否子戈 2018-09-07 18:15

      转账申请是直接广播给整个网络,矿工也是网络上的一个节点,不同于普通用户的地方是,普通用户的客户端是钱包,矿工的节点客户端内置了挖坑程序,这个程序其实可以完全独立于客户端(事实也是这样),挖到矿确保奖励是打到自己的账户即可。
      挖矿的时候其实是需要先有交易记录的,不是说你挖到矿再把交易打包进去。而且一个区块里面会包含哪些交易记录,在矿工决定开始挖矿的那一刻就已经决定了,后面不能改,改了又得从头挖。

  2. Jeryy 2018-06-08 12:54

    博主您好,真的感谢您的文章,让我对区块链交易方面有了更多的了解 ,我还有的问题想请教下您。

    “现在我们把自己的角色转换为矿工,当我们从自己的内存中收集所有交易,准备打包区块时,发现这里有一条交易有0.01BTC的小费,于是我把它作为本次打包优先考虑的交易记录。由于每个区块的大小限制在1M左右,所有我只选了那些给小费的交易打包进这次区块。而那些未给交易费的交易,在优先考虑完这些有交易费的交易之后,我才会考虑把它们加进来。”

    这里表达的意思是  决定是否将某一个交易信息是否加入区块中,是矿工自己决定的么。 如果是的话 “不过也不用着急,比特币系统中只留给了这种优先级高的交易50k的存储空间,即使你没有给交易费,也可能在24小时内被打包进区块” 您这句话又怎么理解呢。

    • 否子戈 2018-06-08 20:01

      是否将某个交易打包进挖的那个区块确实是矿工自己决定的,所以才会有51%攻击,当你手上控制了超过51%的算力,你就决定了整个网络哪些交易可以被加入到区块链,哪些可能永远都不会。
      这和“只保留50K”并不矛盾,那50K是给有手续费的交易的,即使你机器里面还有其他包含了手续费的交易,你也加不到这个块里面来,剩下的大部分空间都是留给你机器上其他交易记录的。因为一次打包不一定可以把当前网络未进链的交易都装进来,所以还有一些交易被留在了网络中,当新块产生之后,这些交易都发起者会去检查,如果自己都交易没有进块,客户端会再次广播自己的交易。一般情况下,产生时间越早的交易会被优先打包,(虽然有些矿工可能把某个节点列入了黑名单,但其他矿工也有可能抢到记账权),24小时足以给这些交易进链的时间。要是正常网速情况下,过了24小时没进链,就说明整个网络可能面临风险,因为现在好像还无法取消一笔发出的交易。

      • Jeryy 2018-06-08 20:07

        好的 谢谢解答

  3. cp 2018-04-22 00:01

    博主您好,首先感谢您的文章,让我了解了很多交易知识。
    我是抱着“在打包开始之前,这些交易记录是以什么方式存在于网络?”这个问题找到您的文章,在文章中对于这个问题,您提到“当我们从自己的内存中收集所有交易,准备打包区块时,发现这里有一条交易有0.01BTC的小费……”这里的“内存”应该就是交易打包之前交易记录存在方式,但是还是对“内存”的概念不理解,我猜测应该不会真的是电脑的RAM吧?如果不是,那这个“内存”又是以什么方式存在与网络呢?矿工获取到交易请求的记录是伴随在新区块内,还是存在另一种和区块无关的数据用于交易请求记录的广播呢?谢谢。

    • 否子戈 2018-04-22 15:15

      说实话,写这篇文章的时候,我也是从别人的文章读到相关的内容,大致有有一点感知,自己也不是很了解。

      现在可以简单说下,比特币的本地数据存储体系主要分两部分,一部分是不可更改的blockchain,另一部分是网络相关信息chainstate,而这个chainstate主要就是用来保存通过网络广播或点对点请求的数据,不过既然是state数据,就是可变的,比如原本chainstate里面保存着一条交易记录,但是当该交易被打包进区块链并被确认之后,就可以从chainstate数据中删除了。chainstate里面保存着自己本机客户端的信息,也保存着网络中其他客户端发过来的信息,如果由于网络或机器原因,chainstate数据丢失了,就需要通过其他节点进行恢复。chainstate在本地客户端是以leveldb作为底层数据库的。不过这块我也还是一知半解,可以参考这篇文章 https://baya.github.io/2017/09/04/build-our-btc-system.html

      矿工首先是收集要创建区块的各种信息,会从本地的chainstate中挑选出部分交易出来,挑选出多少条由自己的算法决定,但整个区块的容量不超过1M,对这些交易按照特定顺序排列后做merkle,得到的merkle hash root,和其他信息如时间戳、nonce等一起进行求区块hash的运算,得到合理的hash之后,就可以把所有这些东西组装在一起,按照比特币的数据存储结构算法生成比特币内部的区块文件,着就是一个区块了。所以,在一个区块没有产生之前,这些交易数据是保存在chainstate里面的,也可以理解为你说的“和区块(链本身)无关”。

  4. yinming 2018-04-19 15:47

    博主您好,观点有些出入:
    挖矿成功产生的hash值代表的区块的所有信息,应该包含了交易信息。为了保证区块未被篡改。在区块接收到上一个区块广播出的hash验证合理后,开始计算下一块hash,根据情况加入收到的交易信息。直到完成POW证明。代表区块已经产生(挖矿成功)。

    • 否子戈 2018-04-20 15:07

      你说的没错,交易信息确实是通过merkle计算在区块hash里面的,我的表述有问题,改一下