【源码阅读】交易池txs_list

1、accountSet

go 复制代码
type accountSet struct {
	accounts map[types.Address]struct{}
	cache    *[]types.Address
}

accountSet 只是一组用于检查是否存在的地址,以及一个能够从交易中派生地址的签名者。

as *accountSet

1.1newAccountSet

go 复制代码
func newAccountSet(addrs ...types.Address) *accountSet

newAccountSet 创建一个带有关联签名者的新地址集,用于派生发件人。

  • 创建一个新的accountSet对象
  • 创建一个空映射并赋值给as.accounts
  • 并将传入的地址使用for range addrs添加到该对象的accounts映射中。

1.2 as.contains

go 复制代码
func (as *accountSet) contains(addr types.Address) bool {
	_, exist := as.accounts[addr]
	return exist
}

contains 检查给定地址是否包含在集合中。

1.3 as.empty

go 复制代码
func (as *accountSet) empty() bool {
	return len(as.accounts) == 0
}

返回集合是否为空。

1.4 as.containsTx

go 复制代码
func (as *accountSet) containsTx(tx *transaction.Transaction) bool {
	return as.contains(*tx.From())
}

containsTx 检查给定 tx 的发送者是否在集合内,通过*tx.From获取到给定交易的发送方地址。 如果无法派生发送者,则此方法返回 false。

1.5 as.add

go 复制代码
func (as *accountSet) add(addr types.Address) {
	as.accounts[addr] = struct{}{}
	as.cache = nil
}

add 将新地址插入要跟踪的集合中。

1.6 as.addTx

go 复制代码
func (as *accountSet) addTx(tx *transaction.Transaction) {
	as.add(*tx.From())
}

将给定交易的发送方插入到集合中,通过*tx.From获取到给定交易的发送方地址。

1.7 as.flatten

go 复制代码
func (as *accountSet) flatten() []types.Address {
	if as.cache == nil {
		accounts := make([]types.Address, 0, len(as.accounts))
		for account := range as.accounts {
			accounts = append(accounts, account)
		}
		as.cache = &accounts
	}
	return *as.cache
}

返回该集合中的地址列表,同时将其缓存以供以后重用。 返回的切片不应更改!该方法的作用是将accountSet中的账户地址展平成一个切片(slice)并返回。

首先检查as.cache是否为空。如果为空,则创建一个新的切片accounts,其长度与as.accounts相同。然后,使用for循环遍历as.accounts中的每个账户地址,并将其添加到accounts切片中。最后,将accounts的地址赋给as.cache,以便下次调用时直接返回缓存的结果。如果as.cache不为空,则直接返回*as.cache,即返回缓存中的切片。

1.8 as.merge

go 复制代码
func (as *accountSet) merge(other *accountSet) {
	for addr := range other.accounts {
		as.accounts[addr] = struct{}{}
	}
	as.cache = nil
}

merge 将"other"集中的所有地址添加到"as"中。

2、txLookup

go 复制代码
type txLookup struct {
	slots   int
	lock    sync.RWMutex
	locals  map[types.Hash]*transaction.Transaction
	remotes map[types.Hash]*transaction.Transaction
}
  • slots:一个整数类型的变量,表示插槽数量。
  • lock:一个sync.RWMutex类型的变量,用于实现读写互斥锁,确保对结构体内部数据的线程安全访问。
  • locals:一个map[types.Hash]*transaction.Transaction类型的变量,表示本地交易的哈希值到交易对象的映射。
  • remotes:一个map[types.Hash]*transaction.Transaction类型的变量,表示远程交易的哈希值到交易对象的映射。
    private
    txLookup 由 TxPool 内部使用来跟踪事务,同时允许在没有互斥锁争用的情况下进行查找。
    注意,虽然这种类型受到了适当的保护以防止并发访问,但它 是一种应该被改变甚至暴露在事务池之外的类型,因为它的内部状态与池的内部机制紧密耦合。 该类型的唯一目的是允许对 TxPool.Get 中的池进行出界查看 ,而无需获取广泛范围的 TxPool.mu 互斥锁。
    t *txLookup

2.1 newTxLookup

go 复制代码
func newTxLookup() *txLookup {
	return &txLookup{
		locals:  make(map[types.Hash]*transaction.Transaction),
		remotes: make(map[types.Hash]*transaction.Transaction),
	}
}

newTxLookup 创建一个带有关联签名者的新地址集,用于派生发件人。

  • 通过调用make函数创建了两个空的映射(map),分别命名为locals和remotes
  • 它们的键类型为types.Hash,值类型为*transaction.Transaction
  • 将这两个映射作为参数传递给txLookup结构体的构造函数,并返回该结构体实例的地址。

2.2 t.Range

go 复制代码
func (t *txLookup) Range(f func(hash types.Hash, tx *transaction.Transaction, local bool) bool, local bool, remote bool) {
	t.lock.RLock()
	defer t.lock.RUnlock()

	if local {
		for key, value := range t.locals {
			if !f(key, value, true) {
				return
			}
		}
	}
	if remote {
		for key, value := range t.remotes {
			if !f(key, value, false) {
				return
			}
		}
	}
}

Range 在映射中的每个键和值上调用 f。 传递的回调应返回是否需要继续迭代的指示符。

调用者需要指定要迭代的集合(或两者)。

  • 通过t.lock.RLock()txLookup结构体的锁进行读锁定。
  • 然后,根据传入的布尔值参数local,分别遍历本地和远程的交易映射。
  • 对于每个交易映射中的键值对,它会调用传入的函数f,并将键、值和一个布尔值local作为参数传递给该函数。这个布尔值表示当前遍历的是本地还是远程的交易。如果函数f返回false,则立即终止遍历并返回。

2.3 t.Get

go 复制代码
func (t *txLookup) Get(hash types.Hash) *transaction.Transaction {
	t.lock.RLock()
	defer t.lock.RUnlock()

	if tx := t.locals[hash]; tx != nil {
		return tx
	}
	return t.remotes[hash]
}

这个方法的作用是在一个事务查找器中查找指定哈希值的交易,优先从本地存储中查找,如果没有找到则从远程存储中查找。

  • 通过t.lock.RLock()txLookup结构体的锁进行读锁定。
  • 根据hash在本地交易中进行查找,有则返回
  • 没有就在远程交易中查找

2.3.1 t.GetLocal

go 复制代码
func (t *txLookup) GetLocal(hash types.Hash) *transaction.Transaction {
	t.lock.RLock()
	defer t.lock.RUnlock()

	return t.locals[hash]
}

根据hash在本地交易中进行查找,返回交易or nil

2.3.1 t.GetRemote

go 复制代码
func (t *txLookup) GetRemote(hash types.Hash) *transaction.Transaction {
	t.lock.RLock()
	defer t.lock.RUnlock()

	return t.remotes[hash]
}

根据hash在远程交易中进行查找,返回交易or nil

2.4 t.Count

go 复制代码
func (t *txLookup) Count() int {
	t.lock.RLock()
	defer t.lock.RUnlock()

	return len(t.locals) + len(t.remotes)
}
  • 通过t.lock.RLock()txLookup结构体的锁进行读锁定
  • 返回查找中的当前事务数
    同理通过t.LocalCountt.RemoteCount可以获得对于的本地和远程的事务数。

2.5 t.Slots

go 复制代码
func (t *txLookup) Slots() int {
	t.lock.RLock()
	defer t.lock.RUnlock()

	return t.slots
}
  • 通过t.lock.RLock()txLookup结构体的锁进行读锁定
  • 返回查找中的当前插槽数

2.6 t.Add

go 复制代码
func (t *txLookup) Add(tx *transaction.Transaction, local bool)

将给定的交易添加到lookup中

  • 通过t.lock.RLock()txLookup结构体的锁进行读锁定
  • 通过t.slots += numSlots(tx)修改slots
  • 获取交易的hash
  • 结合传入的参数local 确定加入到local 中还是remote

2.7 t.Remove

go 复制代码
func (t *txLookup) Remove(hash types.Hash)

根据hash将给定的交易从lookup中删除

  • 通过t.lock.RLock()txLookup结构体的锁进行读锁定
  • 先从本地存储中查找该交易tx, ok := t.locals[hash]
  • 如果找不到就从远程存储中查找tx, ok = t.remotes[hash]
  • 远程中也没有就直接return
  • 找到交易之后,通过t.slots -= numSlots(tx)修改slots
  • 使用delete函数分别从本地存储和远程存储中删除指定的哈希值对应的交易。

2.8 t.RemoteToLocals

go 复制代码
func (t *txLookup) RemoteToLocals(locals *accountSet) int

将属于给定本地的事务迁移到本地集合。 假设局部变量集是线程安全的。

  • 通过t.lock.RLock()txLookup结构体的锁进行读锁定
  • 定义migrated来对迁移的个数进行记录
  • 遍历remotes里面的事务,使用locals.containsTx()(参考1.4)判断该交易的发送发是否在本地列表中,如果是,就将该交易加入locals中t.locals[hash] = tx,并且通过delete从remotes中删除
  • 返回记录的migrated

2.9 t.RemotesBelowTip

go 复制代码
func (t *txLookup) RemotesBelowTip(threshold uint256.Int) []*transaction.Transaction

找到所有低于给定阈值的远程交易并返回。

  • 定义found用于存储符合要求的交易最后return
  • 调用t.Range遍历整个交易(参考2.2),其中参数1的函数f为
go 复制代码
func(hash types.Hash, tx *transaction.Transaction, local bool) bool {
		if tx.GasPrice().Cmp(&threshold) < 0 {
			found = append(found, tx)
		}
		return true
	},

这段代码表示当交易的gasprice低于给定的阈值的时候,将该交易加入到found中,并return true

参数2的local为false,参数3的remote为true

3、TxByNonce、nonceHeap

按照nonce对交易列表进行排序

4、txsSortedMap

go 复制代码
type txsSortedMap struct {
	items map[uint64]*transaction.Transaction // hash map
	index *nonceHeap                          //
	cache []*transaction.Transaction          // Cache
}
  1. items:一个类型为map[uint64]*transaction.Transaction的哈希映射,用于存储交易。
  2. index:一个类型为*nonceHeap的指针,表示一个非重复堆(nonce heap),用于对交易进行排序。
  3. cache:一个类型为[]*transaction.Transaction的切片,用于缓存交易。
    txSortedMap 用来存储同一个账户下的所有交易。
    *m txsSortedMap

4.1 newTxSortedMap

go 复制代码
func newTxSortedMap() *txsSortedMap {
	return &txsSortedMap{
		items: make(map[uint64]*transaction.Transaction),
		index: new(nonceHeap),
	}
}

创建一个新的根据nonce排序的交易映射

4.2 m.Get

go 复制代码
func (m *txsSortedMap) Get(nonce uint64) *transaction.Transaction

返回与给定nonce关联的当前交易。

4.3 m.Put

go 复制代码
func (m *txsSortedMap) Put(tx *transaction.Transaction)
  • 获取交易对象的Nonce值tx.Nonce
  • 检查该Nonce值是否已经存在于items哈希映射中。如果不存在,则将该Nonce值推入index非重复堆中。
  • 将交易对象存储在items哈希映射中,并将缓存清空。m.items[nonce], m.cache = tx, nil

4.4 m.Forward

go 复制代码
func (m *txsSortedMap) Forward(threshold uint64) []*transaction.Transaction

接收一个无符号64位整数类型的参数threshold,并返回一个包含多个交易对象的切片。从堆中弹出元素,直到达到阈值threshold。这个方法的作用是从一个有序的交易集合中移除那些序列号小于给定阈值的交易对象,并返回被移除的交易对象列表。

  1. 创建一个空的切片removed,用于存储被移除的交易对象。
  2. 使用循环从堆m.index中弹出元素,直到堆为空或堆顶元素的值不小于阈值threshold
  3. 在每次循环中,将弹出的元素的值作为键,对应的交易对象从哈希映射m.items中删除,并将其添加到removed切片中。
  4. 如果存在缓存顺序m.cache,从其中删除removed对应的一部分。
  5. 最后,返回removed切片,其中包含了被移除的交易对象。

4.5 m.Filter

go 复制代码
func (m *txsSortedMap) Filter(filter func(*transaction.Transaction) bool) []*transaction.Transaction

Filter 接收 filter 函数,删除所有使得 m.filter 函数调用返回 true 的交易,返回这些被移除的交易。removed := m.filter(filter)

如果事务被删除,堆和缓存就会被破坏,就需要通过m.reheap重新构建堆和缓存。

4.5.1 m.filter

go 复制代码
func (m *txsSortedMap) filter(filter func(*transaction.Transaction) bool) []*transaction.Transaction

filterFilter 相同,但重新生成堆。 仅当立即调用 Filter 或 reheap() 时才应使用此方法。

  • 创建removed用来保存被删除的交易
  • 遍历所有的交易,查找使得传入参数的函数func filter的返回值为true的交易if filter(tx)存入removed中removed = append(removed, tx),并从items中删除delete(m.items, nonce)
  • 当有交易被满足,被删除之后,要将cache缓存清空m.cache = nil

4.5.2 m.reheap

go 复制代码
func (m *txsSortedMap) reheap()

该方法的作用是重新构建堆并清空缓存,这个方法通常用于在修改txsSortedMap结构体的内容后,重新调整堆的顺序以保持正确的顺序。

  • 创建一个新的切片*m.index,其长度为0,并将m.items的长度作为初始容量
  • 遍历m.items的键值对,将每个键(即nonce)添加到*m.index
  • 使用heap.Init函数初始化堆,传入m.index作为参数heap.Init(m.index)
  • 清空cache缓存m.cache = nil

4.6 m.Cap

go 复制代码
func (m *txsSortedMap) Cap(threshold int) []*transaction.Transaction

Cap 根据 threshold 参数对 items 参数进行限制,删除超出的交易,重建堆,返回这些被移除的交易。

  • 如果len<threshold,则直接返回nil
  • 创建drops存储要被删除的交易,用于函数返回
  • 根据index进行排序sort.Sort(*m.index)
  • 循环迭代直到len<threshold,对要删除的交易存入drops中,使用delete删除delete(m.items, (*m.index)[size-1])
  • 修改index*m.index = (*m.index)[:threshold]
  • 使用heap.Init函数初始化堆,传入m.index作为参数heap.Init(m.index)
  • 如果有cache,要对cache进行修改更新m.cache = m.cache[:len(m.cache)-len(drops)]

4.7 m.Remove

go 复制代码
func (m *txsSortedMap) Remove(nonce uint64) bool

根据 nonce 从堆里移除交易,如果没有这个交易返回 false。

并且清空cache:m.cache = nil

4.8 m.Ready

go 复制代码
func (m *txsSortedMap) Ready(start uint64) []*transaction.Transaction

Ready 返回从指定 nonce 开始,连续的交易,并将其删除。

  • 如果堆空或者堆顶元素已经大于start来,直接返回nil
  • 否则创建ready存储符合条件的交易进行函数的返回
  • 使用循环查找符合条件的交易(循环的条件是索引的长度大于0且堆顶index等于当前处理的交易的nonce值,也就是连续)
  • 将符合要求的交易加入ready中ready = append(ready, m.items[next])
  • 从items中删除delete(m.items, next)
  • heap.Pop函数从堆中弹出该交易的nonce值
  • 清空cache并将ready返回

4.9 m.Len

go 复制代码
func (m *txsSortedMap) Len() int {
	return len(m.items)
}

返回映射的长度

4.10 m.Flatten

go 复制代码
func (m *txsSortedMap) Flatten() []*transaction.Transaction

返回一个基于 nonce 排序的交易列表,缓存到 cache 字段里,排序结果将被缓存,以备在对内容进行任何修改之前再次请求时使用。

  • 通过m.fltten方法获得排序的交易缓存列表cache
  • 创建txs,并将cache中的数据复制到txs中,并作为函数返回

4.10.1 m.flatten

go 复制代码
func (m *txsSortedMap) flatten() []*transaction.Transaction
  • 如果cache缓存不存在,则需要进行创建
  • 将items中的交易复制到cache中
  • 使用sort.Sort(TxByNonce(m.cache))对cache中的交易进行排序并返回

4.11 m.LastElement

go 复制代码
func (m *txsSortedMap) LastElement() *transaction.Transaction

返回根据flatten排序结果cache := m.flatten()的最后一个元素return cache[len(cache)-1],也就是有最大nonce的交易

5、txsList

go 复制代码
type txsList struct {
	strict  bool
	txs     *txsSortedMap
	costcap uint256.Int
	gascap  uint64
}

*l txsList

txsList 是属于帐户的交易"列表",按帐户nonce排序,用于存储连续的可执行交易。

  1. strict:布尔类型,表示是否严格遵循交易列表的规则。
  2. txs:指向txsSortedMap类型的指针,表示交易列表中的交易数据。
  3. costcapuint256.Int类型,表示交易列表的成本上限。
  4. gascapuint64类型,表示交易列表的气体上限。

5.1 newTxsList

go 复制代码
func newTxsList(strict bool) *txsList {
	return &txsList{
		strict:  strict,
		txs:     newTxSortedMap(),
		costcap: *uint256.NewInt(0),
	}
}

newtxsList 创建一个新的交易列表,用于维护可随机索引的快速、有间隙、可排序的交易列表。

接受一个布尔类型的参数strict,并返回一个指向txsList类型的指针。

5.2 l.Overlaps

go 复制代码
func (l *txsList) Overlaps(tx *transaction.Transaction) bool {
	return l.txs.Get(tx.Nonce()) != nil
}

返回指定的交易是否与列表中已包含的交易是否具有相同的随机数。(唯一)

5.3 l.Add

go 复制代码
func (l *txsList) Add(tx *transaction.Transaction, priceBump uint64) (bool, *transaction.Transaction)

Add 尝试将新交易插入列表中,返回该交易是否被接受,如果是,则返回它替换的任何先前交易。

如果新交易被接受到列表中,列表的成本和气体阈值也可能会更新。

  1. 如果旧的交易比新交易好,就丢弃新交易,返回false
  2. 接受新交易需要修改新的GasFeeCap和GasTipCap,并且确保新交易的费用上限都要大于旧的

thresholdFeeCap = oldFC * (100 + priceBump) / 100

thresholdFeeCap =oldTip * (100 + priceBump) / 100

  1. 修改成本阈值和气体阈值
go 复制代码
if l.costcap.Cmp(cost) < 0 {
	l.costcap = *cost
}
if gas := tx.Gas(); l.gascap < gas {
	l.gascap = gas
}

5.4 l.Forward

go 复制代码
func (l *txsList) Forward(threshold uint64) []*transaction.Transaction

删除所有nonce比给定的阈值threshold小的交易,调用txs.Forward来完成(参考4.4)

5.5 I.Filter

go 复制代码
func (l *txsList) Filter(costLimit uint256.Int, gasLimit uint64) ([]*transaction.Transaction, []*transaction.Transaction)

Filter 方法根据参数 cost 或 gasLimit 的值移除所有比该值更高的交易,被移除的交易会返回以便进一步处理。

此方法使用缓存的 costcap 和 Gascap 来快速确定计算所有成本是否有一个点,或者余额是否涵盖所有成本。 如果阈值低于 costgas 上限,则在删除新失效的交易后,上限将重置为新高。

该方法接收两个参数:costLimitgasLimit,分别表示交易费用上限和交易的气体限制。方法的返回值是两个切片,分别包含被过滤掉的交易和无效的交易。

  1. 检查所有交易是否都低于阈值,如果是,则直接返回空切片
    if l.costcap.Cmp(&costLimit) <= 0 && l.gascap <= gasLimit { return nil, nil }
  2. 否则,将costcapgascap设置为传入的阈值
  3. 使用l.txs.Filter方法过滤掉所有超过账户资金的交易(参考4.5),并将它们存储在removed切片中
  4. 如果removed为空,则返回空切片
  5. 创建一个名为invalids的切片,用于存储无效的交易
  6. 如果列表是严格的(即不允许高于最低nonce的交易),则进一步通过l.txs.filter过滤掉高于最低nonce的交易(参考4.5.1),并将它们添加到invalids切片中。
  7. 调用l.txs.reheap()方法重新调整堆结构(参考4.5.2),并返回removedinvalids切片l.txs.reheap()

5.6 l.Cap/Ready/Len/Empty/Flatten/LastElement

go 复制代码
func (l *txsList) Cap(threshold int) []*transaction.Transaction {
	return l.txs.Cap(threshold)
}
func (l *txsList) Ready(start uint64) []*transaction.Transaction {
	return l.txs.Ready(start)
}
func (l *txsList) Len() int {
	return l.txs.Len()
}
func (l *txsList) Empty() bool {
	return l.Len() == 0
}
func (l *txsList) Flatten() []*transaction.Transaction {
	return l.txs.Flatten()
}
func (l *txsList) LastElement() *transaction.Transaction {
	return l.txs.LastElement()
}

都是调用的txs里面的方法,参考4.6、4.8、4.9、4.10、4.11

5.7 l.Remove

go 复制代码
func (l *txsList) Remove(tx *transaction.Transaction) (bool, []*transaction.Transaction)

Remove从维护的列表中删除交易,返回是否找到该交易,并返回因删除而无效的交易(仅限严格模式)。

  1. 调用txs.Remove删除给定的交易,并得到是否删除的标志和返回值(参考4.7)
  2. 如果在严格模式下,要返回所有不可执行的交易(tx.Nonce() > nonce)

6、PriceHeap

go 复制代码
type priceHeap struct {
	baseFee *uint256.Int // heap should always be re-sorted after baseFee is changed
	list    []*transaction.Transaction
}

priceHeap 类似于上面提到的 nonceHeap,不过比较优先级时,优先比较 GasPrice,如果相同则比较 Nonce。

Len、Swap、Less、cmp、push、pop

7、txPricedList

go 复制代码
type txPricedList struct {
	stales int64

	all              *txLookup  // Pointer to the map of all transactions
	urgent, floating priceHeap  // Heaps of prices of all the stored **remote** transactions
	reheapMu         sync.Mutex // Mutex asserts that only one routine is reheaping the list
}

txPricedList 是一个按价格排序的堆,允许以价格递增的方式对交易池内容进行操作。 它是基于 txpool 中的所有交易构建的,但只对远程 部分感兴趣。 这意味着只有远程交易才会被考虑进行跟踪、排序、驱逐等。

使用两个堆进行排序:urgent 紧急堆(基于下一个区块的有效提示)和floating浮动堆(基于gasFeeCap)。 总是选择较大的堆进行驱逐。 从紧急堆中逐出的事务首先被降级到浮动堆中。 在某些情况下(在拥塞期间,当块已满时),紧急堆可以提供更好的包含候选者,而在其他情况下(在基本费用峰值的顶部),浮动堆更好。 当基本费用减少时,它们的行为类似。

7.1 newTxPricedList

go 复制代码
func newTxPricedList(all *txLookup) *txPricedList {
	return &txPricedList{
		all: all,
	}
}

创建一个新*txPricedList

7.2 Put

go 复制代码
func (l *txPricedList) Put(tx *transaction.Transaction, local bool) {
	if local {
		return
	}
	// Insert every new transaction to the urgent heap first; Discard will balance the heaps
	heap.Push(&l.urgent, tx)
}

只针对远程交易,所以如果是local,则直接返回

首先添加到urgent heap中,丢弃的话将会平衡堆

7.3 Removed

go 复制代码
func (l *txPricedList) Removed(count int) {
	// Bump the stale counter, but exit if still too low (< 25%)
	stales := atomic.AddInt64(&l.stales, int64(count))
	if int(stales) <= (len(l.urgent.list)+len(l.floating.list))/4 {
		return
	}
	// Seems we've reached a critical number of stale transactions, reheap
	l.Reheap()
}

通知价格交易列表旧交易已从池中删除。 该列表将仅保留陈旧对象的计数器,并在足够大的事务比例变得陈旧时更新堆。

7.4 Underpriced

go 复制代码
func (l *txPricedList) Underpriced(tx *transaction.Transaction) bool {
	return (l.underpricedFor(&l.urgent, tx) || len(l.urgent.list) == 0) &&
		(l.underpricedFor(&l.floating, tx) || len(l.floating.list) == 0) &&
		(len(l.urgent.list) != 0 || len(l.floating.list) != 0)
}

Underpriced 检查交易是否比当前正在跟踪的最低价格(远程)交易便宜(或一样便宜)。

对于两个队列,定价过低被定义为比所有非空队列中最差的项目(如果有)更差。 如果两个队列都是空的,那么就没有任何东西被低估。如果存在任何一个队列的最差项比给定的交易更好,则认为该交易被低估。如果两个队列都为空,则认为没有交易被低估。

所以具体的比较调用了underpricedFor方法

7.4.1 underpricedFor

go 复制代码
func (l *txPricedList) underpricedFor(h *priceHeap, tx *transaction.Transaction) bool

1。 如果在堆开始时发现过时的价格点,则丢弃。

go 复制代码
for len(h.list) > 0 {
	hash := h.list[0].Hash()
	if l.all.GetRemote(hash) == nil { // Removed or migrated
		atomic.AddInt64(&l.stales, -1)
		heap.Pop(h)
		continue
	}
	break
}
  1. 检查价格堆是否为空。如果为空,则说明没有远程交易,直接返回false。
go 复制代码
if len(h.list) == 0 {
		return false // There is no remote transaction at all.
	}
  1. 如果价格堆不为空,则比较堆顶元素和给定交易的价格。如果堆顶元素的价格比给定交易的价格更低或相等,则认为交易被低估,返回true;否则返回false。

7.5 Discard

go 复制代码
func (l *txPricedList) Discard(slots int, force bool) ([]*transaction.Transaction, bool)

找到价格最低的交易,从价格列表中移除它们,并返回它们以供进一步从整个池中移除。需要注意的是,本地交易不会被考虑用于驱逐。

  • 函数接受两个参数:
    slots:表示要移除的交易数量。
    force:表示是否强制移除交易。如果为true,即使无法为新交易腾出足够的空间,也会移除交易;如果为false,则在无法为新交易腾出足够的空间时,会将已移除的交易重新放回紧急堆中。
  • 函数返回两个值:
    一个包含被移除交易的切片([]*transaction.Transaction)。
    一个布尔值,表示是否成功移除了交易。如果成功移除了交易,则为true;否则为false。
    考虑两种情况:
go 复制代码
if len(l.urgent.list)*floatingRatio > len(l.floating.list)*urgentRatio || floatingRatio == 0

此时从urgent里面移除

  • 从远程交易中获取,如果有就移除,继续;没有就break。
  • 将移除的加入floating中

否则从floating中移除

go 复制代码
if len(l.floating.list) == 0 {break}

都为空的话就break

  • 从远程交易中查找,找到就移除
  • 删除
  • 循环slots
    如果还不能满足,就返回false

7.6 Reheap

参考4.5.2

Reheap根据当前远程事务集强制重建堆。

交易远程交易,local为false,remote为true。

通过将较差的一半事务移动到浮动堆中来平衡两个堆

// 注意:Discard 也会在第一次驱逐之前执行此操作,但 Reheap 可以更有效地执行此操作。 此外,如果浮动队列为空,Underpriced 第一次的工作效果可能会不佳。

go 复制代码
	floatingCount := len(l.urgent.list) * floatingRatio / (urgentRatio + floatingRatio)
	l.floating.list = make([]*transaction.Transaction, floatingCount)
	for i := 0; i < floatingCount; i++ {
		l.floating.list[i] = heap.Pop(&l.urgent).(*transaction.Transaction)
	}
	heap.Init(&l.floating)

7.7 SetBaseFee

go 复制代码
func (l *txPricedList) SetBaseFee(baseFee *uint256.Int) {
	l.urgent.baseFee = baseFee
	l.Reheap()
}

SetBaseFee 更新基本费用并触发重新堆。 请注意,处理新块时,不需要在 SetBaseFee 之前调用 Removed。

相关推荐
天晟科技7 小时前
GameFi的前景:游戏与金融的未来交汇点
游戏·金融·区块链
Roun38 小时前
Web3和区块链如何促进数据透明与隐私保护的平衡
web3·区块链·隐私保护
The_Ticker15 小时前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
程序猿阿伟15 小时前
《C++ 实现区块链:区块时间戳的存储与验证机制解析》
开发语言·c++·区块链
TechubNews15 小时前
Helius:从数据出发,衡量 Solana 的真实去中心化程度
去中心化·区块链
dingzd9516 小时前
Web3的核心技术:区块链如何确保信息安全与共享
web3·去中心化·区块链
清 晨16 小时前
Web3与智能合约:区块链技术下的数字信任体系
web3·区块链·智能合约
CertiK17 小时前
Web3.0安全开发实践:Clarity最佳实践总结
web3·区块链·clarity
加密新世界17 小时前
Move on Sui入门 004-在sui链上发布Coin合约和Faucet Coin合约
区块链
YSGZJJ1 天前
股指期货的套保策略如何精准选择和规避风险?
人工智能·区块链