mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
core/txpool: add pending, queued slots to txpool's stats
This commit is contained in:
parent
41ee96fdfe
commit
e85fb69328
16 changed files with 114 additions and 78 deletions
|
|
@ -1481,8 +1481,8 @@ func (p *BlobPool) Nonce(addr common.Address) uint64 {
|
|||
}
|
||||
|
||||
// Stats retrieves the current pool stats, namely the number of pending and the
|
||||
// number of queued (non-executable) transactions.
|
||||
func (p *BlobPool) Stats() (int, int) {
|
||||
// number of queued (non-executable) transactions, slots.
|
||||
func (p *BlobPool) Stats() (int, int, int, int) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
|
|
@ -1490,7 +1490,7 @@ func (p *BlobPool) Stats() (int, int) {
|
|||
for _, txs := range p.index {
|
||||
pending += len(txs)
|
||||
}
|
||||
return pending, 0 // No non-executable txs in the blob pool
|
||||
return pending, 0, 0, 0 // No non-executable txs in the blob pool
|
||||
}
|
||||
|
||||
// Content retrieves the data content of the transaction pool, returning all the
|
||||
|
|
|
|||
|
|
@ -348,12 +348,17 @@ func (pool *LegacyPool) loop() {
|
|||
// Handle stats reporting ticks
|
||||
case <-report.C:
|
||||
pool.mu.RLock()
|
||||
pending, queued := pool.stats()
|
||||
pending, queued, pendingSlots, queuedSlots := pool.stats()
|
||||
pool.mu.RUnlock()
|
||||
stales := int(pool.priced.stales.Load())
|
||||
|
||||
if pending != prevPending || queued != prevQueued || stales != prevStales {
|
||||
log.Debug("Transaction pool status report", "executable", pending, "queued", queued, "stales", stales)
|
||||
log.Debug(
|
||||
"Transaction pool status report",
|
||||
"executable", pending, "executable slots", pendingSlots,
|
||||
"queued", queued, "queued slots", queuedSlots,
|
||||
"stales", stales,
|
||||
)
|
||||
prevPending, prevQueued, prevStales = pending, queued, stales
|
||||
}
|
||||
|
||||
|
|
@ -448,27 +453,35 @@ func (pool *LegacyPool) Nonce(addr common.Address) uint64 {
|
|||
return pool.pendingNonces.get(addr)
|
||||
}
|
||||
|
||||
// Stats retrieves the current pool stats, namely the number of pending and the
|
||||
// number of queued (non-executable) transactions.
|
||||
func (pool *LegacyPool) Stats() (int, int) {
|
||||
// Stats retrieves the current pool stats, namely the number of pending transactions,
|
||||
// slots, and the number of queued (non-executable) transactions, slots.
|
||||
func (pool *LegacyPool) Stats() (int, int, int, int) {
|
||||
pool.mu.RLock()
|
||||
defer pool.mu.RUnlock()
|
||||
|
||||
return pool.stats()
|
||||
}
|
||||
|
||||
// stats retrieves the current pool stats, namely the number of pending and the
|
||||
// number of queued (non-executable) transactions.
|
||||
func (pool *LegacyPool) stats() (int, int) {
|
||||
// stats retrieves the current pool stats, namely the number of pending transactions,
|
||||
// slots and the number of queued (non-executable) transactions, slots.
|
||||
func (pool *LegacyPool) stats() (int, int, int, int) {
|
||||
pending := 0
|
||||
for _, list := range pool.pending {
|
||||
pending += list.Len()
|
||||
}
|
||||
pendingSlots := 0
|
||||
for _, list := range pool.pending {
|
||||
pendingSlots += list.TotalSlots()
|
||||
}
|
||||
queued := 0
|
||||
for _, list := range pool.queue {
|
||||
queued += list.Len()
|
||||
}
|
||||
return pending, queued
|
||||
queuedSlots := 0
|
||||
for _, list := range pool.queue {
|
||||
queuedSlots += list.TotalSlots()
|
||||
}
|
||||
return pending, queued, pendingSlots, queuedSlots
|
||||
}
|
||||
|
||||
// Content retrieves the data content of the transaction pool, returning all the
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func pricedValuedTransaction(nonce uint64, value int64, gaslimit uint64, gaspric
|
|||
|
||||
func count(t *testing.T, pool *LegacyPool) (pending int, queued int) {
|
||||
t.Helper()
|
||||
pending, queued = pool.stats()
|
||||
pending, queued, _, _ = pool.stats()
|
||||
if err := validatePoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
|
|
@ -58,7 +58,7 @@ func fillPool(t testing.TB, pool *LegacyPool) {
|
|||
// Import the batch and verify that limits have been enforced
|
||||
pool.addRemotesSync(executableTxs)
|
||||
pool.addRemotesSync(nonExecutableTxs)
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
slots := pool.all.Slots()
|
||||
// sanity-check that the test prerequisites are ok (pending full)
|
||||
if have, want := pending, slots; have != want {
|
||||
|
|
@ -87,7 +87,7 @@ func TestTransactionFutureAttack(t *testing.T) {
|
|||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
fillPool(t, pool)
|
||||
pending, _ := pool.Stats()
|
||||
pending, _, _, _ := pool.Stats()
|
||||
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
||||
{
|
||||
key, _ := crypto.GenerateKey()
|
||||
|
|
@ -102,7 +102,7 @@ func TestTransactionFutureAttack(t *testing.T) {
|
|||
t.Logf("pending: %d queued: %d, all: %d\n", newPending, newQueued, pool.all.Slots())
|
||||
}
|
||||
}
|
||||
newPending, _ := pool.Stats()
|
||||
newPending, _, _, _ := pool.Stats()
|
||||
// Pending should not have been touched
|
||||
if have, want := newPending, pending; have < want {
|
||||
t.Errorf("wrong pending-count, have %d, want %d (GlobalSlots: %d)",
|
||||
|
|
@ -123,7 +123,7 @@ func TestTransactionFuture1559(t *testing.T) {
|
|||
|
||||
// Create a number of test accounts, fund them and make transactions
|
||||
fillPool(t, pool)
|
||||
pending, _ := pool.Stats()
|
||||
pending, _, _, _ := pool.Stats()
|
||||
|
||||
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
||||
{
|
||||
|
|
@ -135,7 +135,7 @@ func TestTransactionFuture1559(t *testing.T) {
|
|||
}
|
||||
pool.addRemotesSync(futureTxs)
|
||||
}
|
||||
newPending, _ := pool.Stats()
|
||||
newPending, _, _, _ := pool.Stats()
|
||||
// Pending should not have been touched
|
||||
if have, want := newPending, pending; have != want {
|
||||
t.Errorf("Wrong pending-count, have %d, want %d (GlobalSlots: %d)",
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ func validatePoolInternals(pool *LegacyPool) error {
|
|||
defer pool.mu.RUnlock()
|
||||
|
||||
// Ensure the total transaction set is consistent with pending + queued
|
||||
pending, queued := pool.stats()
|
||||
pending, queued, _, _ := pool.stats()
|
||||
if total := pool.all.Count(); total != pending+queued {
|
||||
return fmt.Errorf("total transaction count %d != %d pending + %d queued", total, pending, queued)
|
||||
}
|
||||
|
|
@ -828,7 +828,7 @@ func TestGapFilling(t *testing.T) {
|
|||
transaction(0, 100000, key),
|
||||
transaction(2, 100000, key),
|
||||
})
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
if pending != 1 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1)
|
||||
}
|
||||
|
|
@ -845,7 +845,7 @@ func TestGapFilling(t *testing.T) {
|
|||
if err := pool.addRemoteSync(transaction(1, 100000, key)); err != nil {
|
||||
t.Fatalf("failed to add gapped transaction: %v", err)
|
||||
}
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != 3 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
||||
}
|
||||
|
|
@ -1029,7 +1029,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) {
|
|||
if err := pool.addRemote(pricedTransaction(1, 100000, big.NewInt(1), remote)); err != nil {
|
||||
t.Fatalf("failed to add remote transaction: %v", err)
|
||||
}
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
if pending != 0 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0)
|
||||
}
|
||||
|
|
@ -1044,7 +1044,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) {
|
|||
time.Sleep(2 * evictionInterval)
|
||||
|
||||
// Transactions should not be evicted from the queue yet since lifetime duration has not passed
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != 0 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0)
|
||||
}
|
||||
|
|
@ -1058,7 +1058,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) {
|
|||
// Wait a bit for eviction to run and clean up any leftovers, and ensure only the local remains
|
||||
time.Sleep(2 * config.Lifetime)
|
||||
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != 0 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0)
|
||||
}
|
||||
|
|
@ -1081,7 +1081,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) {
|
|||
<-pool.requestReset(nil, nil)
|
||||
|
||||
// make sure queue, pending are cleared
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != 0 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0)
|
||||
}
|
||||
|
|
@ -1111,7 +1111,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) {
|
|||
time.Sleep(6 * evictionInterval)
|
||||
|
||||
// All gapped transactions shouldn't be kicked out
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
}
|
||||
|
|
@ -1124,7 +1124,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) {
|
|||
|
||||
// The whole life time pass after last promotion, kick out stale transactions
|
||||
time.Sleep(2 * config.Lifetime)
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
}
|
||||
|
|
@ -1275,7 +1275,7 @@ func TestAllowedTxSize(t *testing.T) {
|
|||
t.Fatalf("expected rejection on oversize transaction")
|
||||
}
|
||||
// Run some sanity checks on the pool internals
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
}
|
||||
|
|
@ -1415,7 +1415,7 @@ func TestRepricing(t *testing.T) {
|
|||
pool.addRemotesSync(txs)
|
||||
pool.addLocal(ltx)
|
||||
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
if pending != 7 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 7)
|
||||
}
|
||||
|
|
@ -1431,7 +1431,7 @@ func TestRepricing(t *testing.T) {
|
|||
// Reprice the pool and check that underpriced transactions get dropped
|
||||
pool.SetGasTip(big.NewInt(2))
|
||||
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
}
|
||||
|
|
@ -1465,7 +1465,7 @@ func TestRepricing(t *testing.T) {
|
|||
if err := pool.addLocal(tx); err != nil {
|
||||
t.Fatalf("failed to add underpriced local transaction: %v", err)
|
||||
}
|
||||
if pending, _ = pool.Stats(); pending != 3 {
|
||||
if pending, _, _, _ = pool.Stats(); pending != 3 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
||||
}
|
||||
if err := validateEvents(events, 1); err != nil {
|
||||
|
|
@ -1536,7 +1536,7 @@ func TestRepricingDynamicFee(t *testing.T) {
|
|||
pool.addRemotesSync(txs)
|
||||
pool.addLocal(ltx)
|
||||
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
if pending != 7 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 7)
|
||||
}
|
||||
|
|
@ -1552,7 +1552,7 @@ func TestRepricingDynamicFee(t *testing.T) {
|
|||
// Reprice the pool and check that underpriced transactions get dropped
|
||||
pool.SetGasTip(big.NewInt(2))
|
||||
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
}
|
||||
|
|
@ -1589,7 +1589,7 @@ func TestRepricingDynamicFee(t *testing.T) {
|
|||
if err := pool.addLocal(tx); err != nil {
|
||||
t.Fatalf("failed to add underpriced local transaction: %v", err)
|
||||
}
|
||||
if pending, _ = pool.Stats(); pending != 3 {
|
||||
if pending, _, _, _ = pool.Stats(); pending != 3 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
||||
}
|
||||
if err := validateEvents(events, 1); err != nil {
|
||||
|
|
@ -1662,10 +1662,10 @@ func TestRepricingKeepsLocals(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
expPending, expQueued := 1000, 1000
|
||||
validate := func() {
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != expPending {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, expPending)
|
||||
}
|
||||
|
|
@ -1735,7 +1735,7 @@ func TestUnderpricing(t *testing.T) {
|
|||
pool.addRemotes(txs)
|
||||
pool.addLocal(ltx)
|
||||
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
if pending != 3 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
||||
}
|
||||
|
|
@ -1770,7 +1770,7 @@ func TestUnderpricing(t *testing.T) {
|
|||
if err := pool.addRemote(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); err != txpool.ErrFutureReplacePending {
|
||||
t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, txpool.ErrFutureReplacePending)
|
||||
}
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
}
|
||||
|
|
@ -1792,7 +1792,7 @@ func TestUnderpricing(t *testing.T) {
|
|||
if err := pool.addLocal(ltx); err != nil {
|
||||
t.Fatalf("failed to add new underpriced local transaction: %v", err)
|
||||
}
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != 3 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
||||
}
|
||||
|
|
@ -1843,7 +1843,7 @@ func TestStableUnderpricing(t *testing.T) {
|
|||
}
|
||||
pool.addRemotesSync(txs)
|
||||
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
if pending != int(config.GlobalSlots) {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, config.GlobalSlots)
|
||||
}
|
||||
|
|
@ -1860,7 +1860,7 @@ func TestStableUnderpricing(t *testing.T) {
|
|||
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil {
|
||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||
}
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != int(config.GlobalSlots) {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, config.GlobalSlots)
|
||||
}
|
||||
|
|
@ -1914,7 +1914,7 @@ func TestUnderpricingDynamicFee(t *testing.T) {
|
|||
pool.addRemotes(txs) // Pend K0:0, K0:1; Que K1:1
|
||||
pool.addLocal(ltx) // +K2:0 => Pend K0:0, K0:1, K2:0; Que K1:1
|
||||
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
if pending != 3 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
||||
}
|
||||
|
|
@ -1948,7 +1948,7 @@ func TestUnderpricingDynamicFee(t *testing.T) {
|
|||
if err := pool.addRemoteSync(tx); err != nil { // +K1:3, -K1:0 => Pend K0:0 K2:0; Que K1:2 K1:3
|
||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||
}
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
}
|
||||
|
|
@ -1970,7 +1970,7 @@ func TestUnderpricingDynamicFee(t *testing.T) {
|
|||
if err := pool.addLocal(ltx); err != nil {
|
||||
t.Fatalf("failed to add new underpriced local transaction: %v", err)
|
||||
}
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != 3 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
||||
}
|
||||
|
|
@ -2022,7 +2022,7 @@ func TestDualHeapEviction(t *testing.T) {
|
|||
}
|
||||
pool.addRemotesSync([]*types.Transaction{tx})
|
||||
}
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
if pending+queued != 20 {
|
||||
t.Fatalf("transaction count mismatch: have %d, want %d", pending+queued, 10)
|
||||
}
|
||||
|
|
@ -2076,7 +2076,7 @@ func TestDeduplication(t *testing.T) {
|
|||
t.Errorf("add %d failed: %v", i, err)
|
||||
}
|
||||
}
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
if pending != 1 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1)
|
||||
}
|
||||
|
|
@ -2096,7 +2096,7 @@ func TestDeduplication(t *testing.T) {
|
|||
t.Errorf("add %d failed: %v", i, err)
|
||||
}
|
||||
}
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != len(txs) {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, len(txs))
|
||||
}
|
||||
|
|
@ -2351,7 +2351,7 @@ func testJournaling(t *testing.T, nolocals bool) {
|
|||
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), remote)); err != nil {
|
||||
t.Fatalf("failed to add remote transaction: %v", err)
|
||||
}
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
if pending != 4 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4)
|
||||
}
|
||||
|
|
@ -2369,7 +2369,7 @@ func testJournaling(t *testing.T, nolocals bool) {
|
|||
pool = New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if queued != 0 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0)
|
||||
}
|
||||
|
|
@ -2396,7 +2396,7 @@ func testJournaling(t *testing.T, nolocals bool) {
|
|||
pool = New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
|
||||
pending, queued = pool.Stats()
|
||||
pending, queued, _, _ = pool.Stats()
|
||||
if pending != 0 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0)
|
||||
}
|
||||
|
|
@ -2445,7 +2445,7 @@ func TestStatusCheck(t *testing.T) {
|
|||
// Import the transaction and ensure they are correctly added
|
||||
pool.addRemotesSync(txs)
|
||||
|
||||
pending, queued := pool.Stats()
|
||||
pending, queued, _, _ := pool.Stats()
|
||||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,10 +53,11 @@ func (h *nonceHeap) Pop() interface{} {
|
|||
// sortedMap is a nonce->transaction hash map with a heap based index to allow
|
||||
// iterating over the contents in a nonce-incrementing way.
|
||||
type sortedMap struct {
|
||||
items map[uint64]*types.Transaction // Hash map storing the transaction data
|
||||
index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode)
|
||||
cache types.Transactions // Cache of the transactions already sorted
|
||||
cacheMu sync.Mutex // Mutex covering the cache
|
||||
items map[uint64]*types.Transaction // Hash map storing the transaction data
|
||||
index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode)
|
||||
cache types.Transactions // Cache of the transactions already sorted
|
||||
cacheMu sync.Mutex // Mutex covering the cache
|
||||
totalslots int // Total number of slots of all transactions in the list
|
||||
}
|
||||
|
||||
// newSortedMap creates a new nonce-sorted transaction map.
|
||||
|
|
@ -78,7 +79,11 @@ func (m *sortedMap) Put(tx *types.Transaction) {
|
|||
nonce := tx.Nonce()
|
||||
if m.items[nonce] == nil {
|
||||
heap.Push(m.index, nonce)
|
||||
} else {
|
||||
m.totalslots -= numSlots(m.items[nonce])
|
||||
}
|
||||
|
||||
m.totalslots += numSlots(tx)
|
||||
m.cacheMu.Lock()
|
||||
m.items[nonce], m.cache = tx, nil
|
||||
m.cacheMu.Unlock()
|
||||
|
|
@ -94,6 +99,7 @@ func (m *sortedMap) Forward(threshold uint64) types.Transactions {
|
|||
for m.index.Len() > 0 && (*m.index)[0] < threshold {
|
||||
nonce := heap.Pop(m.index).(uint64)
|
||||
removed = append(removed, m.items[nonce])
|
||||
m.totalslots -= numSlots(m.items[nonce])
|
||||
delete(m.items, nonce)
|
||||
}
|
||||
// If we had a cached order, shift the front
|
||||
|
|
@ -139,6 +145,7 @@ func (m *sortedMap) filter(filter func(*types.Transaction) bool) types.Transacti
|
|||
for nonce, tx := range m.items {
|
||||
if filter(tx) {
|
||||
removed = append(removed, tx)
|
||||
m.totalslots -= numSlots(m.items[nonce])
|
||||
delete(m.items, nonce)
|
||||
}
|
||||
}
|
||||
|
|
@ -192,6 +199,7 @@ func (m *sortedMap) Remove(nonce uint64) bool {
|
|||
break
|
||||
}
|
||||
}
|
||||
m.totalslots -= numSlots(m.items[nonce])
|
||||
delete(m.items, nonce)
|
||||
m.cacheMu.Lock()
|
||||
m.cache = nil
|
||||
|
|
@ -216,6 +224,7 @@ func (m *sortedMap) Ready(start uint64) types.Transactions {
|
|||
var ready types.Transactions
|
||||
for next := (*m.index)[0]; m.index.Len() > 0 && (*m.index)[0] == next; next++ {
|
||||
ready = append(ready, m.items[next])
|
||||
m.totalslots -= numSlots(m.items[next])
|
||||
delete(m.items, next)
|
||||
heap.Pop(m.index)
|
||||
}
|
||||
|
|
@ -452,6 +461,11 @@ func (l *list) LastElement() *types.Transaction {
|
|||
return l.txs.LastElement()
|
||||
}
|
||||
|
||||
// TotalSlots returns total slots of transaction list.
|
||||
func (l *list) TotalSlots() int {
|
||||
return l.txs.totalslots
|
||||
}
|
||||
|
||||
// subTotalCost subtracts the cost of the given transactions from the
|
||||
// total cost of all transactions.
|
||||
func (l *list) subTotalCost(txs []*types.Transaction) {
|
||||
|
|
|
|||
|
|
@ -107,8 +107,8 @@ type SubPool interface {
|
|||
Nonce(addr common.Address) uint64
|
||||
|
||||
// Stats retrieves the current pool stats, namely the number of pending and the
|
||||
// number of queued (non-executable) transactions.
|
||||
Stats() (int, int)
|
||||
// number of queued (non-executable) transactions, slots.
|
||||
Stats() (pending, queued, pendingSlots, queuedSlots int)
|
||||
|
||||
// Content retrieves the data content of the transaction pool, returning all the
|
||||
// pending as well as queued transactions, grouped by account and sorted by nonce.
|
||||
|
|
|
|||
|
|
@ -342,16 +342,18 @@ func (p *TxPool) Nonce(addr common.Address) uint64 {
|
|||
}
|
||||
|
||||
// Stats retrieves the current pool stats, namely the number of pending and the
|
||||
// number of queued (non-executable) transactions.
|
||||
func (p *TxPool) Stats() (int, int) {
|
||||
var runnable, blocked int
|
||||
// number of queued (non-executable) transactions, slots.
|
||||
func (p *TxPool) Stats() (int, int, int, int) {
|
||||
var runnable, blocked, runnableSlots, blockedSlots int
|
||||
for _, subpool := range p.subpools {
|
||||
run, block := subpool.Stats()
|
||||
run, block, runSlots, blockSlots := subpool.Stats()
|
||||
|
||||
runnable += run
|
||||
blocked += block
|
||||
runnableSlots += runSlots
|
||||
blockedSlots += blockSlots
|
||||
}
|
||||
return runnable, blocked
|
||||
return runnable, blocked, runnableSlots, blockedSlots
|
||||
}
|
||||
|
||||
// Content retrieves the data content of the transaction pool, returning all the
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ func (b *EthAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (
|
|||
return b.eth.txPool.Nonce(addr), nil
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) Stats() (runnable int, blocked int) {
|
||||
func (b *EthAPIBackend) Stats() (pending, queued, pendingSlots, queuedSlots int) {
|
||||
return b.eth.txPool.Stats()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ type backend interface {
|
|||
CurrentHeader() *types.Header
|
||||
HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
|
||||
GetTd(ctx context.Context, hash common.Hash) *big.Int
|
||||
Stats() (pending int, queued int)
|
||||
Stats() (pending, queued, pendingSlots, pendingQueued int)
|
||||
SyncProgress() ethereum.SyncProgress
|
||||
}
|
||||
|
||||
|
|
@ -741,7 +741,7 @@ type pendStats struct {
|
|||
// it to the stats server.
|
||||
func (s *Service) reportPending(conn *connWrapper) error {
|
||||
// Retrieve the pending count from the local blockchain
|
||||
pending, _ := s.backend.Stats()
|
||||
pending, _, _, _ := s.backend.Stats()
|
||||
// Assemble the transaction stats and send it to the server
|
||||
log.Trace("Sending pending transactions to ethstats", "count", pending)
|
||||
|
||||
|
|
|
|||
|
|
@ -211,10 +211,12 @@ func (s *TxPoolAPI) ContentFrom(addr common.Address) map[string]map[string]*RPCT
|
|||
|
||||
// Status returns the number of pending and queued transaction in the pool.
|
||||
func (s *TxPoolAPI) Status() map[string]hexutil.Uint {
|
||||
pending, queue := s.b.Stats()
|
||||
pending, queue, pendingSlots, queuedSlots := s.b.Stats()
|
||||
return map[string]hexutil.Uint{
|
||||
"pending": hexutil.Uint(pending),
|
||||
"queued": hexutil.Uint(queue),
|
||||
"pending": hexutil.Uint(pending),
|
||||
"queued": hexutil.Uint(queue),
|
||||
"pending slots": hexutil.Uint(pendingSlots),
|
||||
"queued slots": hexutil.Uint(queuedSlots),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -569,7 +569,7 @@ func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction {
|
|||
func (b testBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
func (b testBackend) Stats() (pending int, queued int) { panic("implement me") }
|
||||
func (b testBackend) Stats() (pending, queued, pendingSlots, queuedSlots int) { panic("implement me") }
|
||||
func (b testBackend) TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ type Backend interface {
|
|||
GetPoolTransactions() (types.Transactions, error)
|
||||
GetPoolTransaction(txHash common.Hash) *types.Transaction
|
||||
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
|
||||
Stats() (pending int, queued int)
|
||||
Stats() (pending, queued, pendingSlots, queuedSlots int)
|
||||
TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction)
|
||||
TxPoolContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction)
|
||||
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ func (b *backendMock) GetPoolTransaction(txHash common.Hash) *types.Transaction
|
|||
func (b *backendMock) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
func (b *backendMock) Stats() (pending int, queued int) { return 0, 0 }
|
||||
func (b *backendMock) Stats() (pending, queued, pendingSlots, queuedSlots int) { return 0, 0, 0, 0 }
|
||||
func (b *backendMock) TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -219,8 +219,13 @@ func (b *LesApiBackend) GetPoolNonce(ctx context.Context, addr common.Address) (
|
|||
return b.eth.txPool.GetNonce(ctx, addr)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) Stats() (pending int, queued int) {
|
||||
return b.eth.txPool.Stats(), 0
|
||||
func (b *LesApiBackend) Stats() (pending, queued, pendingSlots, queuedSlots int) {
|
||||
pending = b.eth.txPool.Stats()
|
||||
|
||||
// For simplicity, just return number of pending transactions in pending slots
|
||||
// without calculating the exact number of slots here
|
||||
pendingSlots = pending
|
||||
return pending, 0, pendingSlots, 0
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) {
|
||||
|
|
|
|||
|
|
@ -652,12 +652,12 @@ func testTransactionStatus(t *testing.T, protocol int) {
|
|||
}
|
||||
// wait until TxPool processes the inserted block
|
||||
for i := 0; i < 10; i++ {
|
||||
if pending, _ := server.handler.txpool.Stats(); pending == 1 {
|
||||
if pending, _, _, _ := server.handler.txpool.Stats(); pending == 1 {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
if pending, _ := server.handler.txpool.Stats(); pending != 1 {
|
||||
if pending, _, _, _ := server.handler.txpool.Stats(); pending != 1 {
|
||||
t.Fatalf("pending count mismatch: have %d, want 1", pending)
|
||||
}
|
||||
// Discard new block announcement
|
||||
|
|
@ -677,12 +677,12 @@ func testTransactionStatus(t *testing.T, protocol int) {
|
|||
}
|
||||
// wait until TxPool processes the reorg
|
||||
for i := 0; i < 10; i++ {
|
||||
if pending, _ := server.handler.txpool.Stats(); pending == 3 {
|
||||
if pending, _, _, _ := server.handler.txpool.Stats(); pending == 3 {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
if pending, _ := server.handler.txpool.Stats(); pending != 3 {
|
||||
if pending, _, _, _ := server.handler.txpool.Stats(); pending != 3 {
|
||||
t.Fatalf("pending count mismatch: have %d, want 3", pending)
|
||||
}
|
||||
// Discard new block announcement
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ func main() {
|
|||
nonces[index]++
|
||||
|
||||
// Wait if we're too saturated
|
||||
if pend, _ := backend.TxPool().Stats(); pend > 2048 {
|
||||
if pend, _, _, _ := backend.TxPool().Stats(); pend > 2048 {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue