mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 04:36:42 +00:00
core/txpool: add validation for func SetGasPrice
This commit is contained in:
parent
7aae33eacf
commit
0737df6c7d
2 changed files with 123 additions and 0 deletions
|
|
@ -257,6 +257,17 @@ func (p *TxPool) loop(head *types.Header) {
|
||||||
// SetGasTip updates the minimum gas tip required by the transaction pool for a
|
// SetGasTip updates the minimum gas tip required by the transaction pool for a
|
||||||
// new transaction, and drops all transactions below this threshold.
|
// new transaction, and drops all transactions below this threshold.
|
||||||
func (p *TxPool) SetGasTip(tip *big.Int) {
|
func (p *TxPool) SetGasTip(tip *big.Int) {
|
||||||
|
if tip == nil {
|
||||||
|
log.Warn("SetGasTip called with nil tip")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if tip.Sign() <= 0 {
|
||||||
|
log.Warn("SetGasTip called with non-positive tip", "tip", tip)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if tip.Cmp(big.NewInt(1_000_000_000_000_000)) > 0 {
|
||||||
|
log.Warn("SetGasTip called with very high tip", "tip", tip)
|
||||||
|
}
|
||||||
for _, subpool := range p.subpools {
|
for _, subpool := range p.subpools {
|
||||||
subpool.SetGasTip(tip)
|
subpool.SetGasTip(tip)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
112
core/txpool/txpool_setgastip_test.go
Normal file
112
core/txpool/txpool_setgastip_test.go
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
package txpool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mockSubPool is a lightweight test double implementing the SubPool interface
|
||||||
|
// used to observe SetGasTip invocations.
|
||||||
|
type mockSubPool struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
callCount int
|
||||||
|
lastTip *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockSubPool) Filter(tx *types.Transaction) bool { return false }
|
||||||
|
func (m *mockSubPool) FilterType(kind byte) bool { return false }
|
||||||
|
func (m *mockSubPool) Init(gasTip uint64, head *types.Header, reserver Reserver) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *mockSubPool) Close() error { return nil }
|
||||||
|
func (m *mockSubPool) Reset(oldHead, newHead *types.Header) {}
|
||||||
|
func (m *mockSubPool) SetGasTip(tip *big.Int) {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
m.callCount++
|
||||||
|
if tip == nil {
|
||||||
|
m.lastTip = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// copy value
|
||||||
|
m.lastTip = new(big.Int).Set(tip)
|
||||||
|
}
|
||||||
|
func (m *mockSubPool) Has(hash common.Hash) bool { return false }
|
||||||
|
func (m *mockSubPool) Get(hash common.Hash) *types.Transaction { return nil }
|
||||||
|
func (m *mockSubPool) GetRLP(hash common.Hash) []byte { return nil }
|
||||||
|
func (m *mockSubPool) GetMetadata(hash common.Hash) *TxMetadata { return nil }
|
||||||
|
func (m *mockSubPool) ValidateTxBasics(tx *types.Transaction) error { return nil }
|
||||||
|
func (m *mockSubPool) Add(txs []*types.Transaction, sync bool) []error { return nil }
|
||||||
|
func (m *mockSubPool) Pending(filter PendingFilter) map[common.Address][]*LazyTransaction {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *mockSubPool) SubscribeTransactions(ch chan<- core.NewTxsEvent, reorgs bool) event.Subscription {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *mockSubPool) Nonce(addr common.Address) uint64 { return 0 }
|
||||||
|
func (m *mockSubPool) Stats() (int, int) { return 0, 0 }
|
||||||
|
func (m *mockSubPool) Content() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
func (m *mockSubPool) ContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
func (m *mockSubPool) Status(hash common.Hash) TxStatus { return TxStatusUnknown }
|
||||||
|
func (m *mockSubPool) Clear() {}
|
||||||
|
|
||||||
|
func TestSetGasTip(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
tip *big.Int
|
||||||
|
expectInvokes int
|
||||||
|
}{
|
||||||
|
{"nil tip", nil, 0},
|
||||||
|
{"zero tip", big.NewInt(0), 0},
|
||||||
|
{"negative tip", big.NewInt(-1), 0},
|
||||||
|
{"very high tip", big.NewInt(1_000_000_000_000_001), 2},
|
||||||
|
{"valid tip", big.NewInt(5), 2},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
m1 := &mockSubPool{}
|
||||||
|
m2 := &mockSubPool{}
|
||||||
|
p := &TxPool{
|
||||||
|
subpools: []SubPool{m1, m2},
|
||||||
|
}
|
||||||
|
// call SetGasTip under test
|
||||||
|
p.SetGasTip(tc.tip)
|
||||||
|
|
||||||
|
// verify invocation counts
|
||||||
|
m1.mu.Lock()
|
||||||
|
got1 := m1.callCount
|
||||||
|
m1.mu.Unlock()
|
||||||
|
m2.mu.Lock()
|
||||||
|
got2 := m2.callCount
|
||||||
|
m2.mu.Unlock()
|
||||||
|
|
||||||
|
if got1+got2 != tc.expectInvokes {
|
||||||
|
t.Fatalf("unexpected total SetGasTip invocations: got %d want %d", got1+got2, tc.expectInvokes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// when invoked, ensure the lastTip equals the passed tip (for non-nil)
|
||||||
|
if tc.tip != nil && tc.expectInvokes > 0 {
|
||||||
|
// pick one mock to assert
|
||||||
|
m1.mu.Lock()
|
||||||
|
if m1.lastTip == nil {
|
||||||
|
t.Fatalf("expected lastTip set on subpool but was nil")
|
||||||
|
}
|
||||||
|
if m1.lastTip.Cmp(tc.tip) != 0 {
|
||||||
|
t.Fatalf("lastTip mismatch: got %v want %v", m1.lastTip, tc.tip)
|
||||||
|
}
|
||||||
|
m1.mu.Unlock()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue