alow multiple slots transactions

This commit is contained in:
Michael Riabzev 2019-11-07 10:17:21 +02:00 committed by Péter Szilágyi
parent 315c239f06
commit de111ef4b7
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
3 changed files with 54 additions and 11 deletions

View file

@ -494,11 +494,11 @@ func (l *txPricedList) Underpriced(tx *types.Transaction, local *accountSet) boo
// Discard finds a number of most underpriced transactions, removes them from the // Discard finds a number of most underpriced transactions, removes them from the
// priced list and returns them for further removal from the entire pool. // priced list and returns them for further removal from the entire pool.
func (l *txPricedList) Discard(count int, local *accountSet) types.Transactions { func (l *txPricedList) Discard(numSlots int, local *accountSet) types.Transactions {
drop := make(types.Transactions, 0, count) // Remote underpriced transactions to drop drop := make(types.Transactions, 0, numSlots) // Remote underpriced transactions to drop
save := make(types.Transactions, 0, 64) // Local underpriced transactions to keep save := make(types.Transactions, 0, 64) // Local underpriced transactions to keep
for len(*l.items) > 0 && count > 0 { for len(*l.items) > 0 && numSlots > 0 {
// Discard stale transactions if found during cleanup // Discard stale transactions if found during cleanup
tx := heap.Pop(l.items).(*types.Transaction) tx := heap.Pop(l.items).(*types.Transaction)
if l.all.Get(tx.Hash()) == nil { if l.all.Get(tx.Hash()) == nil {
@ -510,7 +510,7 @@ func (l *txPricedList) Discard(count int, local *accountSet) types.Transactions
save = append(save, tx) save = append(save, tx)
} else { } else {
drop = append(drop, tx) drop = append(drop, tx)
count-- numSlots -= NumSlots(tx)
} }
} }
for _, tx := range save { for _, tx := range save {

View file

@ -584,7 +584,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
return false, ErrUnderpriced return false, ErrUnderpriced
} }
// New transaction is better than our worse ones, make room for it // New transaction is better than our worse ones, make room for it
drop := pool.priced.Discard(pool.all.Count()-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals) drop := pool.priced.Discard(pool.all.SlotsUsed()-int(pool.config.GlobalSlots+pool.config.GlobalQueue)+NumSlots(tx), pool.locals)
for _, tx := range drop { for _, tx := range drop {
log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice()) log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice())
underpricedTxMeter.Mark(1) underpricedTxMeter.Mark(1)
@ -1143,8 +1143,8 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
pool.pendingNonces = newTxNoncer(statedb) pool.pendingNonces = newTxNoncer(statedb)
pool.currentMaxGas = newHead.GasLimit pool.currentMaxGas = newHead.GasLimit
// Heuristic limit, reject transactions over 32KB to prevent DOS attacks // Heuristic limit, reject transactions over 4 slots to prevent DOS attacks
pool.maxTxSize = 32 * 1024 pool.maxTxSize = 4 * slotSize
// Inject any transactions discarded due to reorgs // Inject any transactions discarded due to reorgs
log.Debug("Reinjecting stale transactions", "count", len(reinject)) log.Debug("Reinjecting stale transactions", "count", len(reinject))
@ -1498,6 +1498,7 @@ func (as *accountSet) merge(other *accountSet) {
// TxPool.mu mutex. // TxPool.mu mutex.
type txLookup struct { type txLookup struct {
all map[common.Hash]*types.Transaction all map[common.Hash]*types.Transaction
numUsedSlots int
lock sync.RWMutex lock sync.RWMutex
} }
@ -1505,6 +1506,7 @@ type txLookup struct {
func newTxLookup() *txLookup { func newTxLookup() *txLookup {
return &txLookup{ return &txLookup{
all: make(map[common.Hash]*types.Transaction), all: make(map[common.Hash]*types.Transaction),
numUsedSlots: 0,
} }
} }
@ -1536,11 +1538,32 @@ func (t *txLookup) Count() int {
return len(t.all) return len(t.all)
} }
// SlotsUsed returns the current number of slots used in the lookup.
func (t *txLookup) SlotsUsed() int {
t.lock.RLock()
defer t.lock.RUnlock()
return t.numUsedSlots
}
const (
// Transactions are kept in slots.
// Each slot is defined to be 32KB.
// This slots mechanism provides protection against
// resources over consumption.
slotSize = 32 * 1024
)
func NumSlots(tx *types.Transaction) int {
return int(math.Ceil(float64(tx.Size()) / slotSize))
}
// Add adds a transaction to the lookup. // Add adds a transaction to the lookup.
func (t *txLookup) Add(tx *types.Transaction) { func (t *txLookup) Add(tx *types.Transaction) {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
t.numUsedSlots += NumSlots(tx)
t.all[tx.Hash()] = tx t.all[tx.Hash()] = tx
} }
@ -1549,5 +1572,6 @@ func (t *txLookup) Remove(hash common.Hash) {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
t.numUsedSlots -= NumSlots(t.all[hash])
delete(t.all, hash) delete(t.all, hash)
} }

View file

@ -1808,6 +1808,25 @@ func TestTransactionStatusCheck(t *testing.T) {
} }
} }
// Test the transaction slots consumption is computed correctly
func TestNumSlots(t *testing.T) {
t.Parallel()
key, _ := crypto.GenerateKey()
tinyTx := pricedDataTransaction(0, 0, big.NewInt(0), key, 0)
if NumSlots(tinyTx) != 1 {
t.Fatalf("Small transactions are expected to consume a single slot.")
}
numAdditionalSlots := rand.Intn(10)
dataLen := uint64(slotSize * numAdditionalSlots)
severalSlotsTx := pricedDataTransaction(0, 0, big.NewInt(0), key, dataLen)
if actual := NumSlots(severalSlotsTx); actual != 1+numAdditionalSlots {
t.Fatalf("Unexpected slots consumptions: expected %d, actual %d", 1+numAdditionalSlots, actual)
}
}
// Benchmarks the speed of validating the contents of the pending queue of the // Benchmarks the speed of validating the contents of the pending queue of the
// transaction pool. // transaction pool.
func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) } func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) }