【源码阅读】交易池txs_list

这篇具有很好参考价值的文章主要介绍了【源码阅读】交易池txs_list。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、accountSet

type accountSet struct {
	accounts map[types.Address]struct{}
	cache    *[]types.Address
}

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

1.1newAccountSet

func newAccountSet(addrs ...types.Address) *accountSet

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

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

1.2 as.contains

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

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

1.3 as.empty

func (as *accountSet) empty() bool {
	return len(as.accounts) == 0
}

返回集合是否为空。

1.4 as.containsTx

func (as *accountSet) containsTx(tx *transaction.Transaction) bool {
	return as.contains(*tx.From())
}

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

1.5 as.add

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

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

1.6 as.addTx

func (as *accountSet) addTx(tx *transaction.Transaction) {
	as.add(*tx.From())
}

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

1.7 as.flatten

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

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

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

2、txLookup

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

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

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

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

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

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

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

func (t *txLookup) Slots() int {
	t.lock.RLock()
	defer t.lock.RUnlock()

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

2.6 t.Add

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

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

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

func (t *txLookup) RemotesBelowTip(threshold uint256.Int) []*transaction.Transaction

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

  • 定义found用于存储符合要求的交易最后return
  • 调用t.Range遍历整个交易(参考2.2),其中参数1的函数f为
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

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

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

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

4.2 m.Get

func (m *txsSortedMap) Get(nonce uint64) *transaction.Transaction

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

4.3 m.Put

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

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

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

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

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

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

func (m *txsSortedMap) Remove(nonce uint64) bool

根据 nonce 从堆里移除交易,如果没有这个交易返回 false。
并且清空cache:m.cache = nil

4.8 m.Ready

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

func (m *txsSortedMap) Len() int {
	return len(m.items)
}

返回映射的长度

4.10 m.Flatten

func (m *txsSortedMap) Flatten() []*transaction.Transaction

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

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

4.10.1 m.flatten

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

4.11 m.LastElement

func (m *txsSortedMap) LastElement() *transaction.Transaction

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

5、txsList

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

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

newtxsList 创建一个新的交易列表,用于维护可随机索引的快速、有间隙、可排序的交易列表。
接受一个布尔类型的参数strict,并返回一个指向txsList类型的指针。

5.2 l.Overlaps

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

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

5.3 l.Add

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. 修改成本阈值和气体阈值
if l.costcap.Cmp(cost) < 0 {
	l.costcap = *cost
}
if gas := tx.Gas(); l.gascap < gas {
	l.gascap = gas
}

5.4 l.Forward

func (l *txsList) Forward(threshold uint64) []*transaction.Transaction

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

5.5 I.Filter

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

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

func (l *txsList) Remove(tx *transaction.Transaction) (bool, []*transaction.Transaction)

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

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

6、PriceHeap

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

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

func newTxPricedList(all *txLookup) *txPricedList {
	return &txPricedList{
		all: all,
	}
}

创建一个新*txPricedList

7.2 Put

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

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

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

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
}
  1. 检查价格堆是否为空。如果为空,则说明没有远程交易,直接返回false。
if len(h.list) == 0 {
		return false // There is no remote transaction at all.
	}
  1. 如果价格堆不为空,则比较堆顶元素和给定交易的价格。如果堆顶元素的价格比给定交易的价格更低或相等,则认为交易被低估,返回true;否则返回false。

7.5 Discard

func (l *txPricedList) Discard(slots int, force bool) ([]*transaction.Transaction, bool)

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

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

此时从urgent里面移除

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

否则从floating中移除

if len(l.floating.list) == 0 {break}

都为空的话就break

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

7.6 Reheap

参考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)

7.7 SetBaseFee

func (l *txPricedList) SetBaseFee(baseFee *uint256.Int) {
	l.urgent.baseFee = baseFee
	l.Reheap()
}

SetBaseFee 更新基本费用并触发重新堆。 请注意,处理新块时,不需要在 SetBaseFee 之前调用 Removed。文章来源地址https://www.toymoban.com/news/detail-779526.html

到了这里,关于【源码阅读】交易池txs_list的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MYSQL+SSM基于区块链的物联网数据交易-46193,免费领源码,【计算机毕业设计开题选题+程序定制+论文书写+答辩ppt书写 全流程 】

    SSM基于区块链的物联网数据交易 系    院 XXXX 学科门类 XXX 专    业  XXX 班级 XXX 学    号 XXX 姓    名 XXX 指导教师 XXX 教师职称 XXX 2022 年 12 月 4 日 摘  要 物联网技术作为继互联网技术后新一代的通信信息集成应用的典范,其巨大的应用前景受到了学术界和政商界的广

    2024年02月05日
    浏览(51)
  • Java基于区块链的物联网数据交易+46193(免费领源码)可做计算机毕业设计JAVA、PHP、爬虫、APP、小程序、C#、C++、python、数据可视化、大数据、全套文案

    SSM基于区块链的物联网数据交易 系    院 XXXX 学科门类 XXX 专    业  XXX 班级 XXX 学    号 XXX 姓    名 XXX 指导教师 XXX 教师职称 XXX 2022 年 12 月 4 日         物联网技术作为继互联网技术后新一代的通信信息集成应用的典范,其巨大的应用前景受到了学术界和政商界

    2024年02月04日
    浏览(45)
  • 对比传统交易模式与基于区块链的交易模式

    随着科技的不断进步,交易模式也在持续革新。传统交易模式与基于区块链的交易模式,作为两种截然不同的交易方式,各有其特点与影响。本文将对这两种交易模式进行详尽的对比,从多个维度揭示它们之间的差异。 传统交易模式通常依赖于中央机构或第三方来进行交易验

    2024年04月27日
    浏览(44)
  • 区块链常见交易问题-高级

    以太坊账户类型 交易部署合约 交易调用合约(ERC20 等) 合约运行报错 合约的gas不足 抛出event的交易 多合约互相调用 Token 与 NFT 数据区别 交易、消息与调用(Message Call)的区别 介绍区块链交易 区块链是一种记录保存系统,在将条目添加到数据链之前会有多个源来验证该条

    2024年02月06日
    浏览(47)
  • 区块链系统:点对点交易原理

    比特币的交易是一种无需信任中介参与的P2P(Peer-to-peer)交易。 传统的电子交易,交易双方必须通过银行这样的信任机构作为中介,这样可以保证交易的安全性,因为银行记录了交易双方的账户资金,能保证在一笔交易中,要么保证成功,要么交易无效,不存在一方到账而另

    2024年02月15日
    浏览(41)
  • 比特币如何运作?区块链、网络、交易

    免责声明:观点来自原文作者,与本人无关,文章仅供参考学习,请自行辨别真伪,切勿跟风,风险自担。 翻译原文:https://www.blockpit.io/blog/how-does-bitcoin-work 比特币是一种革命性的数字货币,由化名中本聪的匿名人士或团体于 2008 年发明。它是世界上第一个加密货币,负责将

    2024年03月24日
    浏览(48)
  • 解析 ETH 区块数据交易input

    这里使用了一个开源项目:https://github.com/rvullriede/evm-abi-decoder 在pom中添加依赖即可: 这个jar需要jdk11,想使用jdk8的同学可以把项目中net.osslabz.evm.abi.definition.AbiDefinition#fromJson(java.lang.String) 的入参 Files.readString(Path.of(abiFilePath)) 改一下,这个Files.readString(Path.of(abiFilePath)) 方法只

    2024年02月22日
    浏览(47)
  • 简易区块链的搭建(3)——交易

    1. UTXO账户模型 产生背景: 为了解决第一类双花问题(一笔钱花两次) 原理介绍: 我们先来介绍传统的金融模式,你有10元存款,想转给我3元,银行会怎么操作? 很显然,他会将你的账户减3元,将我的账户加3元。 这种交易模式记录的是 交易结果 而UTXO账户模型记录的是

    2024年04月09日
    浏览(80)
  • 交易的流动——从钱包到区块链网络

    是否经常会好奇我在钱包上生成的交易是如何一步步流入区块链网络,并最终成为区块的一部分呢? 要想弄清这个问题,首先要搞清楚钱包的工作原理,以主流钱包MetaMask为例,在我们添加一个新的网络时,会需要填写以下信息。MetaMask在会为预置的网络填好这些信息,使用

    2024年02月15日
    浏览(40)
  • 区块链中的交易是什么意思

    id:BSN_2021 公众号:BSN研习社 关于区块链,交易是一个绕不开的话题。区块链可以看做一个不断实时同步的分布式账本,在这个账本上,每一个动作都可以算作一笔“交易”。正是一笔笔交易,才构成了账本的全部。 关于交易,有很多基础术语需要我们了解。 交易/Transaction

    2024年02月06日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包