type accountSet struct {
accounts map[types.Address]struct{}
cache *[]types.Address
}
accountSet 只是一组用于检查是否存在的地址,以及一个能够从交易中派生地址的签名者。
as *accountSet
func newAccountSet(addrs ...types.Address) *accountSet
newAccountSet 创建一个带有关联签名者的新地址集,用于派生发件人。
for range addrs
添加到该对象的accounts映射中。func (as *accountSet) contains(addr types.Address) bool {
_, exist := as.accounts[addr]
return exist
}
contains 检查给定地址是否包含在集合中。
func (as *accountSet) empty() bool {
return len(as.accounts) == 0
}
返回集合是否为空。
func (as *accountSet) containsTx(tx *transaction.Transaction) bool {
return as.contains(*tx.From())
}
containsTx 检查给定 tx 的发送者是否在集合内,通过*tx.From
获取到给定交易的发送方地址。 如果无法派生发送者,则此方法返回 false。
func (as *accountSet) add(addr types.Address) {
as.accounts[addr] = struct{}{}
as.cache = nil
}
add 将新地址插入要跟踪的集合中。
func (as *accountSet) addTx(tx *transaction.Transaction) {
as.add(*tx.From())
}
将给定交易的发送方插入到集合中,通过*tx.From
获取到给定交易的发送方地址。
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,即返回缓存中的切片。
func (as *accountSet) merge(other *accountSet) {
for addr := range other.accounts {
as.accounts[addr] = struct{}{}
}
as.cache = nil
}
merge 将“other”集中的所有地址添加到“as”中。
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
类型的变量,表示远程交易的哈希值到交易对象的映射。func newTxLookup() *txLookup {
return &txLookup{
locals: make(map[types.Hash]*transaction.Transaction),
remotes: make(map[types.Hash]*transaction.Transaction),
}
}
newTxLookup 创建一个带有关联签名者的新地址集,用于派生发件人。
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
,则立即终止遍历并返回。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
结构体的锁进行读锁定。func (t *txLookup) GetLocal(hash types.Hash) *transaction.Transaction {
t.lock.RLock()
defer t.lock.RUnlock()
return t.locals[hash]
}
根据hash在本地交易中进行查找,返回交易or nil
func (t *txLookup) GetRemote(hash types.Hash) *transaction.Transaction {
t.lock.RLock()
defer t.lock.RUnlock()
return t.remotes[hash]
}
根据hash在远程交易中进行查找,返回交易or nil
func (t *txLookup) Count() int {
t.lock.RLock()
defer t.lock.RUnlock()
return len(t.locals) + len(t.remotes)
}
t.lock.RLock()
对txLookup
结构体的锁进行读锁定t.LocalCount
和t.RemoteCount
可以获得对于的本地和远程的事务数。func (t *txLookup) Slots() int {
t.lock.RLock()
defer t.lock.RUnlock()
return t.slots
}
t.lock.RLock()
对txLookup
结构体的锁进行读锁定func (t *txLookup) Add(tx *transaction.Transaction, local bool)
将给定的交易添加到lookup中
t.lock.RLock()
对txLookup
结构体的锁进行读锁定t.slots += numSlots(tx)
修改slotsfunc (t *txLookup) Remove(hash types.Hash)
根据hash将给定的交易从lookup中删除
t.lock.RLock()
对txLookup
结构体的锁进行读锁定tx, ok := t.locals[hash]
tx, ok = t.remotes[hash]
t.slots -= numSlots(tx)
修改slotsdelete
函数分别从本地存储和远程存储中删除指定的哈希值对应的交易。func (t *txLookup) RemoteToLocals(locals *accountSet) int
将属于给定本地的事务迁移到本地集合。 假设局部变量集是线程安全的。
t.lock.RLock()
对txLookup
结构体的锁进行读锁定locals.containsTx()
(参考1.4)判断该交易的发送发是否在本地列表中,如果是,就将该交易加入locals中t.locals[hash] = tx
,并且通过delete从remotes中删除func (t *txLookup) RemotesBelowTip(threshold uint256.Int) []*transaction.Transaction
找到所有低于给定阈值的远程交易并返回。
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
按照nonce对交易列表进行排序
type txsSortedMap struct {
items map[uint64]*transaction.Transaction // hash map
index *nonceHeap //
cache []*transaction.Transaction // Cache
}
items
:一个类型为map[uint64]*transaction.Transaction
的哈希映射,用于存储交易。index
:一个类型为*nonceHeap
的指针,表示一个非重复堆(nonce heap),用于对交易进行排序。cache
:一个类型为[]*transaction.Transaction
的切片,用于缓存交易。func newTxSortedMap() *txsSortedMap {
return &txsSortedMap{
items: make(map[uint64]*transaction.Transaction),
index: new(nonceHeap),
}
}
创建一个新的根据nonce排序的交易映射
func (m *txsSortedMap) Get(nonce uint64) *transaction.Transaction
返回与给定nonce关联的当前交易。
func (m *txsSortedMap) Put(tx *transaction.Transaction)
tx.Nonce
m.items[nonce], m.cache = tx, nil
func (m *txsSortedMap) Forward(threshold uint64) []*transaction.Transaction
接收一个无符号64位整数类型的参数threshold
,并返回一个包含多个交易对象的切片。从堆中弹出元素,直到达到阈值threshold
。这个方法的作用是从一个有序的交易集合中移除那些序列号小于给定阈值的交易对象,并返回被移除的交易对象列表。
removed
,用于存储被移除的交易对象。m.index
中弹出元素,直到堆为空或堆顶元素的值不小于阈值threshold
。m.items
中删除,并将其添加到removed
切片中。m.cache
,从其中删除removed对应的一部分。removed
切片,其中包含了被移除的交易对象。func (m *txsSortedMap) Filter(filter func(*transaction.Transaction) bool) []*transaction.Transaction
Filter 接收 filter 函数,删除所有使得 m.filter 函数调用返回 true 的交易,返回这些被移除的交易。removed := m.filter(filter)
如果事务被删除,堆和缓存就会被破坏,就需要通过m.reheap重新构建堆和缓存。
func (m *txsSortedMap) filter(filter func(*transaction.Transaction) bool) []*transaction.Transaction
filter与Filter相同,但不重新生成堆。 仅当立即调用 Filter 或 reheap() 时才应使用此方法。
func filter
的返回值为true的交易if filter(tx)
存入removed中removed = append(removed, tx)
,并从items中删除delete(m.items, nonce)
m.cache = nil
func (m *txsSortedMap) reheap()
该方法的作用是重新构建堆并清空缓存,这个方法通常用于在修改txsSortedMap
结构体的内容后,重新调整堆的顺序以保持正确的顺序。
*m.index
,其长度为0,并将m.items
的长度作为初始容量m.items
的键值对,将每个键(即nonce)添加到*m.index
中heap.Init
函数初始化堆,传入m.index
作为参数heap.Init(m.index)
func (m *txsSortedMap) Cap(threshold int) []*transaction.Transaction
Cap 根据 threshold 参数对 items 参数进行限制,删除超出的交易,重建堆,返回这些被移除的交易。
len,则直接返回nil
sort.Sort(*m.index)
len,对要删除的交易存入drops中,使用delete删除delete(m.items, (*m.index)[size-1])
*m.index = (*m.index)[:threshold]
heap.Init
函数初始化堆,传入m.index
作为参数heap.Init(m.index)
m.cache = m.cache[:len(m.cache)-len(drops)]
func (m *txsSortedMap) Remove(nonce uint64) bool
根据 nonce 从堆里移除交易,如果没有这个交易返回 false。
并且清空cache:m.cache = nil
func (m *txsSortedMap) Ready(start uint64) []*transaction.Transaction
Ready 返回从指定 nonce 开始,连续的交易,并将其删除。
ready = append(ready, m.items[next])
delete(m.items, next)
heap.Pop
函数从堆中弹出该交易的nonce值func (m *txsSortedMap) Len() int {
return len(m.items)
}
返回映射的长度
func (m *txsSortedMap) Flatten() []*transaction.Transaction
返回一个基于 nonce 排序的交易列表,缓存到 cache 字段里,排序结果将被缓存,以备在对内容进行任何修改之前再次请求时使用。
func (m *txsSortedMap) flatten() []*transaction.Transaction
sort.Sort(TxByNonce(m.cache))
对cache中的交易进行排序并返回func (m *txsSortedMap) LastElement() *transaction.Transaction
返回根据flatten排序结果cache := m.flatten()
的最后一个元素return cache[len(cache)-1]
,也就是有最大nonce的交易
type txsList struct {
strict bool
txs *txsSortedMap
costcap uint256.Int
gascap uint64
}
*l txsList
txsList 是属于帐户的交易“列表”,按帐户nonce排序,用于存储连续的可执行交易。
strict
:布尔类型,表示是否严格遵循交易列表的规则。txs
:指向txsSortedMap
类型的指针,表示交易列表中的交易数据。costcap
:uint256.Int
类型,表示交易列表的成本上限。gascap
:uint64
类型,表示交易列表的气体上限。func newTxsList(strict bool) *txsList {
return &txsList{
strict: strict,
txs: newTxSortedMap(),
costcap: *uint256.NewInt(0),
}
}
newtxsList 创建一个新的交易列表,用于维护可随机索引的快速、有间隙、可排序的交易列表。
接受一个布尔类型的参数strict
,并返回一个指向txsList
类型的指针。
func (l *txsList) Overlaps(tx *transaction.Transaction) bool {
return l.txs.Get(tx.Nonce()) != nil
}
返回指定的交易是否与列表中已包含的交易是否具有相同的随机数。(唯一)
func (l *txsList) Add(tx *transaction.Transaction, priceBump uint64) (bool, *transaction.Transaction)
Add 尝试将新交易插入列表中,返回该交易是否被接受,如果是,则返回它替换的任何先前交易。
如果新交易被接受到列表中,列表的成本和气体阈值也可能会更新。
thresholdFeeCap = oldFC * (100 + priceBump) / 100
thresholdFeeCap =oldTip * (100 + priceBump) / 100
if l.costcap.Cmp(cost) < 0 {
l.costcap = *cost
}
if gas := tx.Gas(); l.gascap < gas {
l.gascap = gas
}
func (l *txsList) Forward(threshold uint64) []*transaction.Transaction
删除所有nonce比给定的阈值threshold小的交易,调用txs.Forward来完成(参考4.4)
func (l *txsList) Filter(costLimit uint256.Int, gasLimit uint64) ([]*transaction.Transaction, []*transaction.Transaction)
Filter 方法根据参数 cost 或 gasLimit 的值移除所有比该值更高的交易,被移除的交易会返回以便进一步处理。
此方法使用缓存的 costcap 和 Gascap 来快速确定计算所有成本是否有一个点,或者余额是否涵盖所有成本。 如果阈值低于 costgas 上限,则在删除新失效的交易后,上限将重置为新高。
该方法接收两个参数:costLimit
和gasLimit
,分别表示交易费用上限和交易的气体限制。方法的返回值是两个切片,分别包含被过滤掉的交易和无效的交易。
if l.costcap.Cmp(&costLimit) <= 0 && l.gascap <= gasLimit { return nil, nil }
costcap
和gascap
设置为传入的阈值l.txs.Filter
方法过滤掉所有超过账户资金的交易(参考4.5),并将它们存储在removed
切片中removed
为空,则返回空切片invalids
的切片,用于存储无效的交易l.txs.filter
过滤掉高于最低nonce的交易(参考4.5.1),并将它们添加到invalids
切片中。l.txs.reheap()
方法重新调整堆结构(参考4.5.2),并返回removed
和invalids
切片l.txs.reheap()
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
func (l *txsList) Remove(tx *transaction.Transaction) (bool, []*transaction.Transaction)
Remove从维护的列表中删除交易,返回是否找到该交易,并返回因删除而无效的交易(仅限严格模式)。
txs.Remove
删除给定的交易,并得到是否删除的标志和返回值(参考4.7)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
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)。 总是选择较大的堆进行驱逐。 从紧急堆中逐出的事务首先被降级到浮动堆中。 在某些情况下(在拥塞期间,当块已满时),紧急堆可以提供更好的包含候选者,而在其他情况下(在基本费用峰值的顶部),浮动堆更好。 当基本费用减少时,它们的行为类似。
func newTxPricedList(all *txLookup) *txPricedList {
return &txPricedList{
all: all,
}
}
创建一个新*txPricedList
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中,丢弃的话将会平衡堆
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()
}
通知价格交易列表旧交易已从池中删除。 该列表将仅保留陈旧对象的计数器,并在足够大的事务比例变得陈旧时更新堆。
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
方法
func (l *txPricedList) underpricedFor(h *priceHeap, tx *transaction.Transaction) bool
1。 如果在堆开始时发现过时的价格点,则丢弃。
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
}
if len(h.list) == 0 {
return false // There is no remote transaction at all.
}
func (l *txPricedList) Discard(slots int, force bool) ([]*transaction.Transaction, bool)
找到价格最低的交易,从价格列表中移除它们,并返回它们以供进一步从整个池中移除。需要注意的是,本地交易不会被考虑用于驱逐。
if len(l.urgent.list)*floatingRatio > len(l.floating.list)*urgentRatio || floatingRatio == 0
此时从urgent里面移除
否则从floating中移除
if len(l.floating.list) == 0 {break}
都为空的话就break
参考4.5.2
Reheap根据当前远程事务集强制重建堆。
交易远程交易,local为false,remote为true。
通过将较差的一半事务移动到浮动堆中来平衡两个堆
// 注意:Discard 也会在第一次驱逐之前执行此操作,但 Reheap 可以更有效地执行此操作。 此外,如果浮动队列为空,Underpriced 第一次的工作效果可能会不佳。
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)
func (l *txPricedList) SetBaseFee(baseFee *uint256.Int) {
l.urgent.baseFee = baseFee
l.Reheap()
}
SetBaseFee 更新基本费用并触发重新堆。 请注意,处理新块时,不需要在 SetBaseFee 之前调用 Removed。