mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
alow multiple slots transactions
This commit is contained in:
parent
315c239f06
commit
de111ef4b7
3 changed files with 54 additions and 11 deletions
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
@ -1497,14 +1497,16 @@ func (as *accountSet) merge(other *accountSet) {
|
||||||
// peeking into the pool in TxPool.Get without having to acquire the widely scoped
|
// peeking into the pool in TxPool.Get without having to acquire the widely scoped
|
||||||
// TxPool.mu mutex.
|
// TxPool.mu mutex.
|
||||||
type txLookup struct {
|
type txLookup struct {
|
||||||
all map[common.Hash]*types.Transaction
|
all map[common.Hash]*types.Transaction
|
||||||
lock sync.RWMutex
|
numUsedSlots int
|
||||||
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// newTxLookup returns a new txLookup structure.
|
// newTxLookup returns a new txLookup structure.
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) }
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue