Skip to content

Commit

Permalink
check block number and timestamp options when filtering conditional t…
Browse files Browse the repository at this point in the history
…ransactions
  • Loading branch information
jj1980a committed Oct 10, 2024
1 parent 0b28bb5 commit 996833c
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 13 deletions.
6 changes: 3 additions & 3 deletions core/txpool/legacypool/legacypool.go
Original file line number Diff line number Diff line change
Expand Up @@ -1655,7 +1655,7 @@ func (pool *LegacyPool) truncateQueue() {
// to trigger a re-heap is this function
func (pool *LegacyPool) demoteUnexecutables() {
// Iterate over all accounts and demote any non-executable transactions
gasLimit := pool.currentHead.Load().GasLimit
currentHeader := pool.currentHead.Load()
for addr, list := range pool.pending {
nonce := pool.currentState.GetNonce(addr)

Expand All @@ -1667,7 +1667,7 @@ func (pool *LegacyPool) demoteUnexecutables() {
log.Trace("Removed old pending transaction", "hash", hash)
}
// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
drops, invalids := list.Filter(pool.currentState.GetBalance(addr), gasLimit)
drops, invalids := list.Filter(pool.currentState.GetBalance(addr), currentHeader.GasLimit)
for _, tx := range drops {
hash := tx.Hash()
log.Trace("Removed unpayable pending transaction", "hash", hash)
Expand All @@ -1683,7 +1683,7 @@ func (pool *LegacyPool) demoteUnexecutables() {
pool.enqueueTx(hash, tx, false, false)
}
// Drop all transactions that no longer have valid TxOptions
txConditionalsRemoved := list.FilterTxConditional(pool.currentState)
txConditionalsRemoved := list.FilterTxConditional(pool.currentState, currentHeader)

for _, tx := range txConditionalsRemoved {
hash := tx.Hash()
Expand Down
24 changes: 18 additions & 6 deletions core/txpool/legacypool/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,14 +523,26 @@ func (l *list) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions,
return removed, invalids
}

// FilterTxConditional returns the conditional transactions with invalid KnownAccounts
// TODO - We will also have to check block range and time stamp range!
func (l *list) FilterTxConditional(state *state.StateDB) types.Transactions {
// FilterTxConditional returns the conditional transactions with invalid PIP15 options
func (l *list) FilterTxConditional(state *state.StateDB, header *types.Header) types.Transactions {
if state == nil || header == nil {
return nil
}

removed := l.txs.filter(func(tx *types.Transaction) bool {
if options := tx.GetOptions(); options != nil {
err := state.ValidateKnownAccounts(options.KnownAccounts)
if err != nil {
log.Error("Error while Filtering Tx Conditional", "err", err)
if err := state.ValidateKnownAccounts(options.KnownAccounts); err != nil {
log.Debug("Error while Filtering Tx Conditional's known accounts", "err", err)
return true
}

if err := header.ValidateBlockNumberOptionsPIP15(options.BlockNumberMin, options.BlockNumberMax); err != nil {
log.Debug("Error while Filtering Tx Conditional's block number options", "err", err)
return true
}

if err := header.ValidateTimestampOptionsPIP15(options.TimestampMin, options.TimestampMax); err != nil {
log.Debug("Error while Filtering Tx Conditional's timestamp options", "err", err)
return true
}

Expand Down
134 changes: 130 additions & 4 deletions core/txpool/legacypool/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,18 @@ func BenchmarkListAdd(b *testing.B) {
}
}

func TestFilterTxConditional(t *testing.T) {
func TestFilterTxConditionalKnownAccounts(t *testing.T) {
t.Parallel()

// Create an in memory state db to test against.
memDb := rawdb.NewMemoryDatabase()
db := state.NewDatabase(memDb)
state, _ := state.New(common.Hash{}, db, nil)

header := &types.Header{
Number: big.NewInt(0),
}

// Create a private key to sign transactions.
key, _ := crypto.GenerateKey()

Expand All @@ -100,7 +104,7 @@ func TestFilterTxConditional(t *testing.T) {

// There should be no drops at this point.
// No state has been modified.
drops := list.FilterTxConditional(state)
drops := list.FilterTxConditional(state, header)

count := len(drops)
require.Equal(t, 0, count, "got %d filtered by TxOptions when there should not be any", count)
Expand All @@ -122,7 +126,7 @@ func TestFilterTxConditional(t *testing.T) {
list.Add(tx2, DefaultConfig.PriceBump)

// There should still be no drops as no state has been modified.
drops = list.FilterTxConditional(state)
drops = list.FilterTxConditional(state, header)

count = len(drops)
require.Equal(t, 0, count, "got %d filtered by TxOptions when there should not be any", count)
Expand All @@ -131,7 +135,129 @@ func TestFilterTxConditional(t *testing.T) {
state.SetState(common.Address{19: 1}, common.Hash{}, common.Hash{31: 1})

// tx2 should be the single transaction filtered out
drops = list.FilterTxConditional(state)
drops = list.FilterTxConditional(state, header)

count = len(drops)
require.Equal(t, 1, count, "got %d filtered by TxOptions when there should be a single one", count)

require.Equal(t, tx2, drops[0], "Got %x, expected %x", drops[0].Hash(), tx2.Hash())
}

func TestFilterTxConditionalBlockNumber(t *testing.T) {
t.Parallel()

// Create an in memory state db to test against.
memDb := rawdb.NewMemoryDatabase()
db := state.NewDatabase(memDb)
state, _ := state.New(common.Hash{}, db, nil)

header := &types.Header{
Number: big.NewInt(100),
}

// Create a private key to sign transactions.
key, _ := crypto.GenerateKey()

// Create a list.
list := newList(true)

// Create a transaction with no defined tx options
// and add to the list.
tx := transaction(0, 1000, key)
list.Add(tx, DefaultConfig.PriceBump)

// There should be no drops at this point.
// No state has been modified.
drops := list.FilterTxConditional(state, header)

count := len(drops)
require.Equal(t, 0, count, "got %d filtered by TxOptions when there should not be any", count)

// Create another transaction with a block number option and add to the list.
tx2 := transaction(1, 1000, key)

var options types.OptionsPIP15

options.BlockNumberMin = big.NewInt(90)
options.BlockNumberMax = big.NewInt(110)

tx2.PutOptions(&options)
list.Add(tx2, DefaultConfig.PriceBump)

// There should still be no drops as no state has been modified.
drops = list.FilterTxConditional(state, header)

count = len(drops)
require.Equal(t, 0, count, "got %d filtered by TxOptions when there should not be any", count)

// Set block number that conflicts with tx2's policy
header.Number = big.NewInt(120)

// tx2 should be the single transaction filtered out
drops = list.FilterTxConditional(state, header)

count = len(drops)
require.Equal(t, 1, count, "got %d filtered by TxOptions when there should be a single one", count)

require.Equal(t, tx2, drops[0], "Got %x, expected %x", drops[0].Hash(), tx2.Hash())
}

func TestFilterTxConditionalTimestamp(t *testing.T) {
t.Parallel()

// Create an in memory state db to test against.
memDb := rawdb.NewMemoryDatabase()
db := state.NewDatabase(memDb)
state, _ := state.New(common.Hash{}, db, nil)

header := &types.Header{
Number: big.NewInt(0),
Time: 100,
}

// Create a private key to sign transactions.
key, _ := crypto.GenerateKey()

// Create a list.
list := newList(true)

// Create a transaction with no defined tx options
// and add to the list.
tx := transaction(0, 1000, key)
list.Add(tx, DefaultConfig.PriceBump)

// There should be no drops at this point.
// No state has been modified.
drops := list.FilterTxConditional(state, header)

count := len(drops)
require.Equal(t, 0, count, "got %d filtered by TxOptions when there should not be any", count)

// Create another transaction with a timestamp option and add to the list.
tx2 := transaction(1, 1000, key)

var options types.OptionsPIP15

minTimestamp := uint64(90)
maxTimestamp := uint64(110)

options.TimestampMin = &minTimestamp
options.TimestampMax = &maxTimestamp

tx2.PutOptions(&options)
list.Add(tx2, DefaultConfig.PriceBump)

// There should still be no drops as no state has been modified.
drops = list.FilterTxConditional(state, header)

count = len(drops)
require.Equal(t, 0, count, "got %d filtered by TxOptions when there should not be any", count)

// Set timestamp that conflicts with tx2's policy
header.Time = 120

// tx2 should be the single transaction filtered out
drops = list.FilterTxConditional(state, header)

count = len(drops)
require.Equal(t, 1, count, "got %d filtered by TxOptions when there should be a single one", count)
Expand Down

0 comments on commit 996833c

Please sign in to comment.