dir : core/txpool/txpool.go
pending중인 tx의 수를 구한다.
pending := uint64(0)
for _, list := range pool.pending {
pending += uint64(list.Len())
}
// slot이 GlobalSlot의 수 이하라면 함수 종료
// GlobalSlot : 모든 account의 executable tx slot의 최대값
if pending <= pool.config.GlobalSlots {
return
}
pendingBeforeCap := pending
본인의 slot을 초과한 account의 tx를 우선적으로 제거한다.
spammers := prque.New(nil)
for addr, list := range pool.pending {
if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots {
spammers.Push(addr, int64(list.Len())
}
}
offender 목록을 만들고, 점진적으로 tx들을 drop해 나간다.
offenders := []commoin.Address{]
// GlobalSlots보다 pending tx가 작거나 같아질때까지 tx를 drop
for pending > pool.configGlobalSlots && !spammers.Empty() {
offender, _ := spammers.Pop()
offenders = append(offenders, offender.(common.Address))
// 각 offender들에 대해 균일하게 임계치 이상의 tx를 제거
if len(offenders) > 1 {
threshold := pool.pending[offender.(common.Address)].Len()
// addr의 tx수가 임게치 이하가 될 때까지 tx 제거
for pending > pool.config.GlobalSlots && pool.pending[offender[len(offenders)-2]].Len() > threshold {
for i := 0; i < len(offenders)-1; i++ {
// 해당 address의 tx list 탐색
list := pool.pending[offenders[i]]
// 초과된 tx 목록을 반환
caps := list.Cap(list.Len() - 1)
for _, tx := range caps {
hash := tx.hash()
pool.all.Remove(hash)
// 해당 addr의 nonce를 가상 db에서 업데이트
pool.pendingNonces.setIfLower(offenders[i], tx.Nonce())
}
// pool의 tx count 업데이트, 전파
pool.priced.Removed(len(caps))
pendingGauge.Dec(int64(len(caps)))
if pool.locals.contains(offenders[i]) {
localGauge.Dec(int64(len(caps)))
}
pending--
}
}
}
}
위에서 tx 수를 줄였음에도 여전히 임계치 이상인 경우, offender들 각각의 초과된 tx들을 제거한다.
if pending > pool.config.GlobalSlots && len(offenders) > 0 {
for pending > pool.config.GlobalSlots && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > pool.config.AccountSlots {
for _, addr := range offenders {
// addr의 tx 목록을 가져옴
list := pool.pending[addr]
// 초과된 tx를 가져옴
caps := list.Cap(list.Len() -1 )
for _, tx := range caps {
hash := tx.Hash()
pool.all.Remove(hash)
// nonce update (drop된 tx 갯수 반영)
pool.pendingNonces.setIflower(addr, tx.Nonce())
}
pool.priced.Removed(len(caps))
pendingGauge.Dec(int64(len(caps)))
if pool.locals.contains(addr) {
localGauge.Dec(int64(len(caps)))
}
pending--
}
}
}
pendingRateLimitMeter.Mark(int64(pendingbeforeCap - pending))
txpool.runReorg()