以太坊源码分析:交易缓冲池txpool

区块链就是何交易打交道,咱们今天就介绍下,交易处理过程当中的一个重要组成部分:txpool。这篇文章主要从功能角度介绍,经过这篇文章会了解:缓存

  1. txpool的在交易中的位置和做用。
  2. txpool的功能,核心组成部分queued和pending。
  3. txpool如何实现它的功能。
  4. txpool源码的重要关注点。

以太坊内部有个重要的内部功能是txpool,从字面意思就能看出来,交易池就是存放交易的池子。它在以太坊中的位置以下图,只要有新交易,不管是本节点建立的,仍是其余peer节点广播来的,都会先加入到交易池里,在打包区块的时候,就从这个池子里提取,区块产生以后,共识区块,交易上链。less

txpool主图

txpool有4个功能:函数

  1. 做为存放交易的缓冲区,大量交易到来时,先存起来
  2. 为打包区块服务,合适交易会被打包到区块
  3. 清理交易
  4. 当交易的数量多于缓冲区大小时,过滤/惩罚发送大量交易的帐户(攻击者)

咱们来一张稍微详细点的模块交互图,看txpool怎么实现上面4个功能的。oop

txpool模块交互

缓存功能的设计

txpool中的交易分为queued和pending 2种,其中queued存放将来的、当前没法执行的交易。以太坊使用nonce值决定某个帐户的交易顺序,多条交易值nonce值必须连续,若是和过去的交易不连续,则没法执行,咱们不妨使用nonce值,标记交易的号码,nonce为10的交易,称为第10号交易。举个例子,当前帐户的nonce是10,txpool中有该帐户的第100号交易,但txpool中没有第11~99号交易,这些交易的缺失,形成第100号交易没法执行,因此第100号交易就是将来的交易、不可执行的交易,存放在queue中。性能

pending存放可执行的交易。好比咱们把上面的11~99号交易补全了,那么11~100号交易均可以进入到pending,由于这些交易都是连续的,均可以打包进区块。区块链

当节点收到交易(本地节点发起的或peer广播来的)时,会先存放到queued,txpool在某些状况下,把queued中可执行的交易,转移到pending中。spa

为区块打包服务

这是txpool最核心的功能,worker在打包区块的时候,会获取全部的pending交易,但这些交易还存在txpool中,worker只是读取出来,至于txpool什么时候删除交易,稍后从txpool清理交易的角度单独在看。设计

清理交易

txpool清理交易有如下几种条件,符合任意如下1条的,都是无效交易,会被从pending或者queued中移除code

  1. 交易的nonce值已经低于帐户在当前高度上的nonce值,表明交易已过时,交易已经上链就属于这种状况
  2. 交易的GasLimit大于区块的GasLimit,区块容不下交易
  3. 帐户的余额已不足以支持该交易要消耗的费用
  4. 交易的数量超过了queued和pending的缓冲区大小,须要进行清理

交易清理主要有3个场景事件

  1. txpool订阅了ChainHeadEvent事件,该事件表明主链上有新区块产生,txpool会根据最新的区块,检查每一个帐号的交易,有些无效的会被删除,有些因为区块回滚会从pending移动到queued,而后把queued中可执行的交易移动到pending,为下一轮区块打包组号准备。
  2. queued交易移动到pending被称为“提高”(promote),这个过程当中,一样会检查交易,当交易不符合以上条件时,就会被直接从queued中删除。
  3. 删除停留在queued中超过3小时的交易,3小时这个超时时间是能够经过geth的启动参数调整的。txpool记录了某个帐户交易进入pending的时间,若是这个时间超过了3小时,表明该帐号的交易迟迟不能被主链打包,既然没法被主连接受,就删除掉在queued中原本就没法执行的交易。

惩罚恶意帐号

这也是txpool很重要的一个属性,能够防止恶意帐户以发起大量垃圾交易。防止恶意用户形成:

  1. 占用txpool空间
  2. 浪费节点大量内存和CPU
  3. 下降打包性能

只有当交易的总数量超过缓冲区大小时,txpool才会认为有恶意帐户发起大量交易。pending和queued缓冲区大小不一样,但处理策略相似:

  1. pending的缓冲区容量是4096,当pending的交易数量多于此时,就会运行检查,每一个帐号的交易数量是否多于16,把这些帐号搜集出来,进行循环依次清理,什么意思呢?就是每轮只删除(移动到queued)这些帐号的每一个帐号1条交易,而后看数量是否降下来了,不知足再进行下一轮,直到知足。
  2. queued的缓冲区容量是1024,超过以后清理策略和pending差很少,但这里但是真删除了。

该部分功能未抽象成单独的函数,而是在promoteExecutables()中,就是在每次把queued交易转移到pending后执行的。

本地交易的特权,txpool虽然对交易有诸多限制,但若是交易是本节点的帐号发起的,以上数量限制等都对他无效。因此,若是你用本节点帐号不停的发送交易,并不会被认为是攻击者,你用txpool.status命令,能够查看到交易的数量,确定能够大于4096,我曾达到过60000+。

重点关注的源码

txpool的主要设计上面就讲完了,若是你想把txpool的代码阅读一番,我建议你重点关注一下这些函数和变量,按图索骥能就彻底掌握txpool的实现。

  • TxPoolConfig:txpool的配置参数
  • chainHeadCh:txpool订阅了新区块事件
  • pending:pending的交易,每一个帐号都有一个交易列表
  • queue:queued的交易,每一个帐号都有一个交易列表
  • loop:txpool的事件处理函数
  • addTx:添加1条交易的源头,你能找到相似的函数
  • promoteExecutables:queued交易移动到pending
  • reset:根据当前区块的最新高度,重置txpool中的交易

仔细阅读一遍,你会发现txpool会涉及多个锁(TxPool.mu, TxPool.all, TxPool.priced.all),因此当txpool中的交易不少时,它的性能是很低的,这也会影响到区块的打包。

  1. 若是这篇文章对你有帮助,请点个赞/喜欢,鼓励我持续分享,感谢。
  2. 个人文章列表,点此可查看
  3. 若是喜欢本文,随意转载,但请保留此原文连接

一块儿学Golang-分享有料的Go语言技术

相关文章
相关标签/搜索