mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-12 23:13:45 +00:00
check block number and timestamp options when filtering conditional transactions
This commit is contained in:
parent
bfede06618
commit
a106bd18f7
3 changed files with 151 additions and 13 deletions
|
|
@ -1673,7 +1673,7 @@ func (pool *LegacyPool) truncateQueue() {
|
||||||
// to trigger a re-heap is this function
|
// to trigger a re-heap is this function
|
||||||
func (pool *LegacyPool) demoteUnexecutables() {
|
func (pool *LegacyPool) demoteUnexecutables() {
|
||||||
// Iterate over all accounts and demote any non-executable transactions
|
// 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 {
|
for addr, list := range pool.pending {
|
||||||
nonce := pool.currentState.GetNonce(addr)
|
nonce := pool.currentState.GetNonce(addr)
|
||||||
|
|
||||||
|
|
@ -1685,7 +1685,7 @@ func (pool *LegacyPool) demoteUnexecutables() {
|
||||||
log.Trace("Removed old pending transaction", "hash", hash)
|
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
|
// 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 {
|
for _, tx := range drops {
|
||||||
hash := tx.Hash()
|
hash := tx.Hash()
|
||||||
log.Trace("Removed unpayable pending transaction", "hash", hash)
|
log.Trace("Removed unpayable pending transaction", "hash", hash)
|
||||||
|
|
@ -1701,7 +1701,7 @@ func (pool *LegacyPool) demoteUnexecutables() {
|
||||||
pool.enqueueTx(hash, tx, false, false)
|
pool.enqueueTx(hash, tx, false, false)
|
||||||
}
|
}
|
||||||
// Drop all transactions that no longer have valid TxOptions
|
// Drop all transactions that no longer have valid TxOptions
|
||||||
txConditionalsRemoved := list.FilterTxConditional(pool.currentState)
|
txConditionalsRemoved := list.FilterTxConditional(pool.currentState, currentHeader)
|
||||||
|
|
||||||
for _, tx := range txConditionalsRemoved {
|
for _, tx := range txConditionalsRemoved {
|
||||||
hash := tx.Hash()
|
hash := tx.Hash()
|
||||||
|
|
|
||||||
|
|
@ -531,14 +531,26 @@ func (l *list) Filter(costLimit *uint256.Int, gasLimit uint64) (types.Transactio
|
||||||
return removed, invalids
|
return removed, invalids
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterTxConditional returns the conditional transactions with invalid KnownAccounts
|
// FilterTxConditional returns the conditional transactions with invalid PIP15 options
|
||||||
// TODO - We will also have to check block range and time stamp range!
|
func (l *list) FilterTxConditional(state *state.StateDB, header *types.Header) types.Transactions {
|
||||||
func (l *list) FilterTxConditional(state *state.StateDB) types.Transactions {
|
if state == nil || header == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
removed := l.txs.filter(func(tx *types.Transaction) bool {
|
removed := l.txs.filter(func(tx *types.Transaction) bool {
|
||||||
if options := tx.GetOptions(); options != nil {
|
if options := tx.GetOptions(); options != nil {
|
||||||
err := state.ValidateKnownAccounts(options.KnownAccounts)
|
if err := state.ValidateKnownAccounts(options.KnownAccounts); err != nil {
|
||||||
if err != nil {
|
log.Debug("Error while Filtering Tx Conditional's known accounts", "err", err)
|
||||||
log.Error("Error while Filtering Tx Conditional", "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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ func BenchmarkListAdd(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFilterTxConditional(t *testing.T) {
|
func TestFilterTxConditionalKnownAccounts(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create an in memory state db to test against.
|
// Create an in memory state db to test against.
|
||||||
|
|
@ -105,6 +105,10 @@ func TestFilterTxConditional(t *testing.T) {
|
||||||
db := state.NewDatabase(memDb)
|
db := state.NewDatabase(memDb)
|
||||||
state, _ := state.New(common.Hash{}, db, nil)
|
state, _ := state.New(common.Hash{}, db, nil)
|
||||||
|
|
||||||
|
header := &types.Header{
|
||||||
|
Number: big.NewInt(0),
|
||||||
|
}
|
||||||
|
|
||||||
// Create a private key to sign transactions.
|
// Create a private key to sign transactions.
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
|
|
||||||
|
|
@ -118,7 +122,7 @@ func TestFilterTxConditional(t *testing.T) {
|
||||||
|
|
||||||
// There should be no drops at this point.
|
// There should be no drops at this point.
|
||||||
// No state has been modified.
|
// No state has been modified.
|
||||||
drops := list.FilterTxConditional(state)
|
drops := list.FilterTxConditional(state, header)
|
||||||
|
|
||||||
count := len(drops)
|
count := len(drops)
|
||||||
require.Equal(t, 0, count, "got %d filtered by TxOptions when there should not be any", count)
|
require.Equal(t, 0, count, "got %d filtered by TxOptions when there should not be any", count)
|
||||||
|
|
@ -151,7 +155,7 @@ func TestFilterTxConditional(t *testing.T) {
|
||||||
list.Add(tx2, DefaultConfig.PriceBump)
|
list.Add(tx2, DefaultConfig.PriceBump)
|
||||||
|
|
||||||
// There should still be no drops as no state has been modified.
|
// There should still be no drops as no state has been modified.
|
||||||
drops = list.FilterTxConditional(state)
|
drops = list.FilterTxConditional(state, header)
|
||||||
|
|
||||||
count = len(drops)
|
count = len(drops)
|
||||||
require.Equal(t, 0, count, "got %d filtered by TxOptions when there should not be any", count)
|
require.Equal(t, 0, count, "got %d filtered by TxOptions when there should not be any", count)
|
||||||
|
|
@ -165,7 +169,129 @@ func TestFilterTxConditional(t *testing.T) {
|
||||||
fmt.Println("after2", trie.Hash())
|
fmt.Println("after2", trie.Hash())
|
||||||
|
|
||||||
// tx2 should be the single transaction filtered out
|
// 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)
|
count = len(drops)
|
||||||
require.Equal(t, 1, count, "got %d filtered by TxOptions when there should be a single one", count)
|
require.Equal(t, 1, count, "got %d filtered by TxOptions when there should be a single one", count)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue