mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
307 lines
9.1 KiB
Go
307 lines
9.1 KiB
Go
package txpool
|
|
|
|
import (
|
|
"errors"
|
|
"math/big"
|
|
"reflect"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/XinFinOrg/XDPoSChain/common"
|
|
"github.com/XinFinOrg/XDPoSChain/core"
|
|
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
|
"github.com/XinFinOrg/XDPoSChain/core/state"
|
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
|
"github.com/XinFinOrg/XDPoSChain/event"
|
|
"github.com/XinFinOrg/XDPoSChain/params"
|
|
)
|
|
|
|
type testChain struct{}
|
|
|
|
func (testChain) Config() *params.ChainConfig { return params.TestChainConfig }
|
|
|
|
func (testChain) CurrentBlock() *types.Header { return &types.Header{Number: big.NewInt(0)} }
|
|
|
|
func (testChain) StateAt(common.Hash) (*state.StateDB, error) {
|
|
return state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()))
|
|
}
|
|
|
|
func (testChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
|
|
return event.NewSubscription(func(quit <-chan struct{}) error {
|
|
<-quit
|
|
return nil
|
|
})
|
|
}
|
|
|
|
type testLocalTracker struct {
|
|
mu sync.Mutex
|
|
events *[]string
|
|
tracked []common.Hash
|
|
}
|
|
|
|
func (t *testLocalTracker) Track(tx *types.Transaction) {
|
|
t.mu.Lock()
|
|
defer t.mu.Unlock()
|
|
*t.events = append(*t.events, "track")
|
|
t.tracked = append(t.tracked, tx.Hash())
|
|
}
|
|
|
|
func (t *testLocalTracker) IsRetryableReject(err error) bool {
|
|
return errors.Is(err, ErrUnderpriced)
|
|
}
|
|
|
|
type testSubPool struct {
|
|
events *[]string
|
|
|
|
lastAdd []*types.Transaction
|
|
lastSync bool
|
|
addErrs []error
|
|
}
|
|
|
|
func (s *testSubPool) Filter(tx *types.Transaction) bool { return true }
|
|
|
|
func (s *testSubPool) Init(gasTip uint64, head *types.Header, reserver Reserver) error { return nil }
|
|
|
|
func (s *testSubPool) Close() error { return nil }
|
|
|
|
func (s *testSubPool) Reset(oldHead, newHead *types.Header) {}
|
|
|
|
func (s *testSubPool) SetGasTip(tip *big.Int) error { return nil }
|
|
|
|
func (s *testSubPool) Has(hash common.Hash) bool { return false }
|
|
|
|
func (s *testSubPool) Get(hash common.Hash) *types.Transaction { return nil }
|
|
|
|
func (s *testSubPool) ValidateTxBasics(tx *types.Transaction) error { return nil }
|
|
|
|
func (s *testSubPool) Add(txs []*types.Transaction, sync bool) []error {
|
|
*s.events = append(*s.events, "add")
|
|
s.lastAdd = txs
|
|
s.lastSync = sync
|
|
if len(s.addErrs) > 0 {
|
|
errs := make([]error, len(txs))
|
|
copy(errs, s.addErrs)
|
|
return errs
|
|
}
|
|
return make([]error, len(txs))
|
|
}
|
|
|
|
func (s *testSubPool) Pending(filter PendingFilter) map[common.Address][]*LazyTransaction {
|
|
return map[common.Address][]*LazyTransaction{}
|
|
}
|
|
|
|
func (s *testSubPool) SubscribeTransactions(ch chan<- core.NewTxsEvent, reorgs bool) event.Subscription {
|
|
return event.NewSubscription(func(quit <-chan struct{}) error {
|
|
<-quit
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (s *testSubPool) Nonce(addr common.Address) uint64 { return 0 }
|
|
|
|
func (s *testSubPool) Stats() (int, int) { return 0, 0 }
|
|
|
|
func (s *testSubPool) Content() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) {
|
|
return map[common.Address][]*types.Transaction{}, map[common.Address][]*types.Transaction{}
|
|
}
|
|
|
|
func (s *testSubPool) ContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (s *testSubPool) Status(hash common.Hash) TxStatus { return TxStatusUnknown }
|
|
|
|
func (s *testSubPool) SetSigner(f func(address common.Address) bool) {}
|
|
|
|
func (s *testSubPool) IsSigner(addr common.Address) bool { return false }
|
|
|
|
func TestAddLocalTracksAfterAdd(t *testing.T) {
|
|
events := []string{}
|
|
tracker := &testLocalTracker{events: &events}
|
|
subpool := &testSubPool{events: &events}
|
|
|
|
pool, err := New(0, testChain{}, []SubPool{subpool})
|
|
if err != nil {
|
|
t.Fatalf("failed to create txpool: %v", err)
|
|
}
|
|
defer pool.Close()
|
|
|
|
pool.SetLocalTracker(tracker)
|
|
|
|
tx := types.NewTransaction(0, common.Address{0x1}, big.NewInt(1), 21000, big.NewInt(1), nil)
|
|
if err := pool.AddLocal(tx, true); err != nil {
|
|
t.Fatalf("AddLocal failed: %v", err)
|
|
}
|
|
|
|
if len(tracker.tracked) != 1 || tracker.tracked[0] != tx.Hash() {
|
|
t.Fatalf("tracker did not receive local tx hash")
|
|
}
|
|
if len(subpool.lastAdd) != 1 || subpool.lastAdd[0].Hash() != tx.Hash() {
|
|
t.Fatalf("subpool Add did not receive local tx")
|
|
}
|
|
if !subpool.lastSync {
|
|
t.Fatalf("sync flag not propagated to subpool Add")
|
|
}
|
|
if !reflect.DeepEqual(events, []string{"add", "track"}) {
|
|
t.Fatalf("unexpected call order: have %v", events)
|
|
}
|
|
}
|
|
|
|
func TestAddLocalMultipleTracksAfterAdd(t *testing.T) {
|
|
events := []string{}
|
|
tracker := &testLocalTracker{events: &events}
|
|
subpool := &testSubPool{events: &events}
|
|
|
|
pool, err := New(0, testChain{}, []SubPool{subpool})
|
|
if err != nil {
|
|
t.Fatalf("failed to create txpool: %v", err)
|
|
}
|
|
defer pool.Close()
|
|
|
|
pool.SetLocalTracker(tracker)
|
|
|
|
tx0 := types.NewTransaction(0, common.Address{0x1}, big.NewInt(1), 21000, big.NewInt(1), nil)
|
|
tx1 := types.NewTransaction(1, common.Address{0x1}, big.NewInt(1), 21000, big.NewInt(1), nil)
|
|
if err := pool.AddLocal(tx0, true); err != nil {
|
|
t.Fatalf("AddLocal tx0 failed: %v", err)
|
|
}
|
|
if err := pool.AddLocal(tx1, true); err != nil {
|
|
t.Fatalf("AddLocal tx1 failed: %v", err)
|
|
}
|
|
|
|
hashes := []common.Hash{tx0.Hash(), tx1.Hash()}
|
|
if len(tracker.tracked) != len(hashes) {
|
|
t.Fatalf("tracker tx count mismatch: have %d, want %d", len(tracker.tracked), len(hashes))
|
|
}
|
|
if !reflect.DeepEqual(tracker.tracked, hashes) {
|
|
t.Fatalf("tracker hashes mismatch: have %v, want %v", tracker.tracked, hashes)
|
|
}
|
|
|
|
if len(subpool.lastAdd) != 1 || subpool.lastAdd[0].Hash() != tx1.Hash() {
|
|
t.Fatalf("subpool Add did not receive second local tx")
|
|
}
|
|
if !subpool.lastSync {
|
|
t.Fatalf("sync flag not propagated to subpool Add")
|
|
}
|
|
if !reflect.DeepEqual(events, []string{"add", "track", "add", "track"}) {
|
|
t.Fatalf("unexpected call order: have %v", events)
|
|
}
|
|
}
|
|
|
|
func TestAddLocalMultipleTracksOnlyAcceptedTransactions(t *testing.T) {
|
|
events := []string{}
|
|
tracker := &testLocalTracker{events: &events}
|
|
subpool := &testSubPool{
|
|
events: &events,
|
|
addErrs: []error{ErrInvalidSender},
|
|
}
|
|
|
|
pool, err := New(0, testChain{}, []SubPool{subpool})
|
|
if err != nil {
|
|
t.Fatalf("failed to create txpool: %v", err)
|
|
}
|
|
defer pool.Close()
|
|
|
|
pool.SetLocalTracker(tracker)
|
|
|
|
tx0 := types.NewTransaction(0, common.Address{0x1}, big.NewInt(1), 21000, big.NewInt(1), nil)
|
|
tx1 := types.NewTransaction(1, common.Address{0x1}, big.NewInt(1), 21000, big.NewInt(1), nil)
|
|
if err := pool.AddLocal(tx0, true); !errors.Is(err, ErrInvalidSender) {
|
|
t.Fatalf("unexpected first error: have %v, want %v", err, ErrInvalidSender)
|
|
}
|
|
subpool.addErrs = nil
|
|
if err := pool.AddLocal(tx1, true); err != nil {
|
|
t.Fatalf("unexpected second error: %v", err)
|
|
}
|
|
|
|
hashes := []common.Hash{tx1.Hash()}
|
|
if !reflect.DeepEqual(tracker.tracked, hashes) {
|
|
t.Fatalf("tracker hashes mismatch: have %v, want %v", tracker.tracked, hashes)
|
|
}
|
|
if !reflect.DeepEqual(events, []string{"add", "add", "track"}) {
|
|
t.Fatalf("unexpected call order: have %v", events)
|
|
}
|
|
}
|
|
|
|
func TestAddLocalTracksOnlyAcceptedTransaction(t *testing.T) {
|
|
events := []string{}
|
|
tracker := &testLocalTracker{events: &events}
|
|
subpool := &testSubPool{
|
|
events: &events,
|
|
addErrs: []error{ErrInvalidSender},
|
|
}
|
|
|
|
pool, err := New(0, testChain{}, []SubPool{subpool})
|
|
if err != nil {
|
|
t.Fatalf("failed to create txpool: %v", err)
|
|
}
|
|
defer pool.Close()
|
|
|
|
pool.SetLocalTracker(tracker)
|
|
|
|
tx := types.NewTransaction(0, common.Address{0x1}, big.NewInt(1), 21000, big.NewInt(1), nil)
|
|
err = pool.AddLocal(tx, true)
|
|
if !errors.Is(err, ErrInvalidSender) {
|
|
t.Fatalf("unexpected error: have %v, want %v", err, ErrInvalidSender)
|
|
}
|
|
|
|
if len(tracker.tracked) != 0 {
|
|
t.Fatalf("tracker should not receive failed local tx, have %d tracked", len(tracker.tracked))
|
|
}
|
|
if !reflect.DeepEqual(events, []string{"add"}) {
|
|
t.Fatalf("unexpected call order: have %v", events)
|
|
}
|
|
}
|
|
|
|
func TestAddLocalTracksTemporaryRejectedTransaction(t *testing.T) {
|
|
events := []string{}
|
|
tracker := &testLocalTracker{events: &events}
|
|
subpool := &testSubPool{
|
|
events: &events,
|
|
addErrs: []error{ErrUnderpriced},
|
|
}
|
|
|
|
pool, err := New(0, testChain{}, []SubPool{subpool})
|
|
if err != nil {
|
|
t.Fatalf("failed to create txpool: %v", err)
|
|
}
|
|
defer pool.Close()
|
|
|
|
pool.SetLocalTracker(tracker)
|
|
|
|
tx := types.NewTransaction(0, common.Address{0x1}, big.NewInt(1), 21000, big.NewInt(1), nil)
|
|
err = pool.AddLocal(tx, true)
|
|
if !errors.Is(err, ErrUnderpriced) {
|
|
t.Fatalf("unexpected error: have %v, want %v", err, ErrUnderpriced)
|
|
}
|
|
|
|
if !reflect.DeepEqual(tracker.tracked, []common.Hash{tx.Hash()}) {
|
|
t.Fatalf("tracker should receive temporary rejected local tx")
|
|
}
|
|
if !reflect.DeepEqual(events, []string{"add", "track"}) {
|
|
t.Fatalf("unexpected call order: have %v", events)
|
|
}
|
|
}
|
|
|
|
func TestAddLocalTemporaryRejectWithoutTrackerReturnsError(t *testing.T) {
|
|
events := []string{}
|
|
subpool := &testSubPool{
|
|
events: &events,
|
|
addErrs: []error{ErrUnderpriced},
|
|
}
|
|
|
|
pool, err := New(0, testChain{}, []SubPool{subpool})
|
|
if err != nil {
|
|
t.Fatalf("failed to create txpool: %v", err)
|
|
}
|
|
defer pool.Close()
|
|
|
|
tx := types.NewTransaction(0, common.Address{0x1}, big.NewInt(1), 21000, big.NewInt(1), nil)
|
|
err = pool.AddLocal(tx, true)
|
|
if !errors.Is(err, ErrUnderpriced) {
|
|
t.Fatalf("unexpected error: have %v, want %v", err, ErrUnderpriced)
|
|
}
|
|
if !reflect.DeepEqual(events, []string{"add"}) {
|
|
t.Fatalf("unexpected call order: have %v", events)
|
|
}
|
|
}
|