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

广告位招租
扫码页面底部二维码联系

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

输入和输出

一个交易在系统里被输入和输出表示。输入是指这笔交易所要进行转移的币来自之前的哪些输出。输出是指这些币将会被发送给哪些地址。在区块链上记账,不是告诉你一个账号现在有多少钱,而是告诉你这个账号当前得到了哪些输出。比如一个地址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 66125

为价值买单,打赏一杯咖啡

本文价值661.25RMB
已有20条评论
  1. Hmm 2021-09-29 10:13

    “当一条交易记录被打包进一个区块之后,就有了一个确认,而这个区块所在的链后面被再加入一个区块,就是第二个确认,如此下去,一个交易有了6个确认,我们就认为这个交易已经确定了,会被永远记录在区块链中。”

    博主好!在最长链中,一个区块后面跟着六个区块,就相当于这个区块被确认了?天下矿工这么多,最长链肯定是一直增长的,满足条件不是相当容易吗?如果在一段时间后还没跟着六个区块,那就扔掉?

    每个块必须达到可容纳的最大交易记录数才能上链吗?如果是的话,一旦网络中充斥着巨额小费但又不可信的交易记录,区块就很难写满;如果不是的话,生成一个块才是主要收入,一个块中随便有几个交易记录就可以上链了。

    初识区块链,请多包涵。

    • 否子戈 2021-09-29 10:30

      区块链网络是由共识机制约束的,你要深刻理解这一点。你的两个问题都是没有理解透这个点。在网络中永远存在多个矿机客户端,且在他们挖矿的时候,别人也在挖矿;同时网络中的客户端永远不可能在同一时刻持有相同的链,比如A客户端的链是~abc,B客户端的链是~afg,他们的链长度相同,但实际区块不同,这是正常现象。但是区块链网络的共识机制,或者说应用网络机制,会不断要求客户端同步网络中存在的最长链。客户端默认会接受这个要求,但是你也可以修改客户端源代码,不同步,如果这类客户端多了,那么网络中就会有多条长链,矿工就不知道自己要用哪一条才好,这个时候,网络就存在风险了,矿工就会罢工。于是,社区的开发者要商量一下,我们用哪一条,如果协调不过来,咱们就只能硬分叉,比如从比特币硬分叉出比特币现金币,以后各自安好,互不相欠,矿工们自己决定今后跟哪个链走。所以,你说的情况是正常情况,系统总会告诉你最后的答案。至于你第二个问题,建议你再读我栏目下的其他文章。如果你给的手续费高,矿工们争着抢,那是可以的,矿工也可以通过修改程序来伪造新交易,甚至上自己的链。但是,你的这条链随着时间的推移会不会是最长链呢?网络会告诉你答案。如果你掌控了整个网络51%算力,那么你就可以拼命算块,于是让你伪造的交易成为最长链的一部分。这个时候,虽然你的交易是伪造成功了,但是,你的这个网络已经没有信用,不会有人再在你的链上记账了。

  2. newiep 2021-07-26 17:37

    楼主好,感谢分享,对区块链的理解更深了一层。文中提到的关于手续费哪里有个小问题。 手续费是在矿工打包时,把所有交易的手续费求和写一笔新的交易记录给到自己,还是每笔交易的手续费都有对应的一笔交易记录给到自己。还是其他的方式,提取手续费到自己的账户

    • 否子戈 2021-08-01 08:11

      可以了解一下找零机制。用户转账的时候,可以主动提供手续费。手续费始终来自交易本身,不可能凭空产生。另外,矿工更想要的是区块奖励,而手续费更多是小费性质。

  3. fett 2021-03-13 10:59

    既然第一个区块不包含交易,那么以后的区块也是可以不包含区块的吧?
    因为现在整个区块链还有挖矿奖励,并且新区块奖励还很大,那么如果区块打包人故意不打包任何交易记录,是否就造成了所有人都无法交易?
    现在区块打包交易的目的是只有交易费这一项好处吧?

    • fett 2021-03-13 11:43

      看了一些相关资料,确实有空块,为什么没有恶化下去呢,如果打包人都产生空块,那么市场不是要爆炸了?

      • 否子戈 2021-03-18 15:29

        其他节点可以选择不接受这个块,自然淘汰

  4. CharmSea 2020-02-29 20:15

    博主你好,我有几个问题不太理解,故此向你请教
    1、用户通过钱包发起交易(输入金额、对方的地址等),然后钱包把交易信息发送给矿工,钱包会不会也将交易的信息发送给对方呢
    2、矿工打包好一个区块后就会广播给其他节点进行验证,那么在此期间该矿工会不会把区块就并入到自己本地的区块链(状况一),还是说要等到其他的节点验证通过后才并入到自己本地的区块链(状况二)
    3、以 状况一 为前提,那么如果这个矿工制作了一个假的区块,那么这个假的区块不就可以在区块链网络里面存在了嘛(被别的节点同步得以传播)
    4、以 状况二 为前提,该矿工怎么知道自己的挖出的区块得到验证 以及 得知验证通过后如何把自己挖到的区块加入本地的区块链(是通过同步其它的区块嘛,还是直接添加)

    • 否子戈 2020-03-01 00:20

      1. 钱包不是定向发送交易,而是将交易广播给网络,能连通的节点都能接收到该交易信息
      2. 你可以这样理解,矿工客户端实际上分为两个体系,一个体系是挖矿用的,另一个体系是区块链本身。挖矿体系从本身接收到的交易广播里面,随便捡一些,凑出一个块的体积,然后开始挖矿。在这个过程里面,它要先去验证每一个交易的输入是否是可信的。如何验证?就是去自己所保存的区块链中去拿去数据,不断的校验。只有确保交易可信之后,才会进行挖矿过程,否则,就是算出来,广播给别的客户端,别的客户端也可以很容易验证出里面包含了不可信交易,会直接把这个块丢掉。
      3. 关于分叉,区块连网络中,随时随地发生着分叉,也就是两个以上矿工同时(短时间内)挖出矿,然后其他节点可能将不同的块加到自己的区块链尾,但是要记住另外一个机制,就是最长链机制,一旦过了一段时间,通过网络同步,节点会选择更长的链同步过来,之前加到尾部的短链上多出来的块会被丢掉。
      4. 区块链上面节点之间是互不信任的,所以,并不是接收到消息就信任消息,而是会做校验,而区块链本身是所有节点共享,所以,要做这个校验只需要从区块链取出数据,没有难度。
      5. 有一种情况非常危险,就是51%攻击,如果整个网络的算力51%被一个人控制,那么这个人就可以修改客户端代码,然后将假交易进行广播、写块,然后利用自己的优势,在其他节点上接受这个假交易,使这个假交易成为名副其实的长链中的交易,基于该假交易的后续交易都是可信交易,导致灾难性的系统失信,所以,你所担心的情况,基本上只有51%攻击能做到。

      • CharmSea 2020-03-08 23:59

        首先十分感谢博主耐心细致的解决了我的疑问,下面是我新产生的疑问
        1、矿工计算出新区快以后会将计算出的区块发送给其他的区块验证,那么将区块发送出去以后,该矿工是基于自己挖出的那个区块继续挖矿 还是 等待验证结果
        2、如果是等待验证结果,那么该矿工如何知道自己挖出的那个区块通过了验证
        3、最重要的问题,矿工计算出一个新区块后,是在什么时候将这个区块添加到自己本地的区块链里面

        • KermNa 2021-05-07 17:37

          好问题,问题解了吗

  5. super 2018-09-07 17:08

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

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

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

  6. 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

        好的 谢谢解答

  7. 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里面的,也可以理解为你说的“和区块(链本身)无关”。

  8. yinming 2018-04-19 15:47

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

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

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