go-ethereum/miner/worker_test.go
Daniel Liu 8850835f6b
perf(core/txpool,miner): speed up pending transaction ordering with uint256 #29008 (#2159)
Switch LazyTransaction gas caps from *big.Int to *uint256.Int and convert once at pending retrieval time.

In miner ordering, keep fee comparisons on uint256 and precompute TRC21 gas price in uint256 form to avoid repeated big-int conversions in heap comparisons.

Also update affected tests and call sites in legacypool/worker/helper paths.

Compatibility: LazyTransaction exported field types changed (GasFeeCap/GasTipCap).
2026-03-11 08:50:56 +05:30

175 lines
4.9 KiB
Go

// Copyright 2026 The XDPoSChain Authors
// This file is part of the XDPoSChain library.
//
// The XDPoSChain library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The XDPoSChain library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the XDPoSChain library. If not, see <http://www.gnu.org/licenses/>.
package miner
import (
"math/big"
"testing"
"time"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/event"
"github.com/XinFinOrg/XDPoSChain/params"
"github.com/holiman/uint256"
)
func newBlockingSubscription() event.Subscription {
return event.NewSubscription(func(unsub <-chan struct{}) error {
<-unsub
return nil
})
}
func TestWorkerUpdateNonXDPoSStaysRunning(t *testing.T) {
worker := &worker{
engine: ethash.NewFaker(),
chainHeadSub: newBlockingSubscription(),
chainSideSub: newBlockingSubscription(),
resetCh: make(chan time.Duration, 1),
}
done := make(chan struct{})
started := make(chan struct{})
go func() {
close(started)
worker.update()
close(done)
}()
select {
case <-started:
// worker.update has started; proceed with timing checks.
case <-time.After(time.Second):
t.Fatal("worker.update did not start in time")
}
select {
case <-done:
t.Fatal("worker.update returned before unsubscribe")
default:
// Expected: update is still running until subscription error.
}
worker.chainHeadSub.Unsubscribe()
select {
case <-done:
// Expected: update exits after subscription error.
case <-time.After(time.Second):
t.Fatal("worker.update did not return after unsubscribe")
}
}
func TestWorkerCheckPreCommitXDPoSMismatch(t *testing.T) {
config := &params.ChainConfig{
ChainID: big.NewInt(1),
XDPoS: &params.XDPoSConfig{
V2: &params.V2{
SwitchBlock: big.NewInt(0),
AllConfigs: map[uint64]*params.V2Config{
0: {MinePeriod: 2},
},
},
},
}
signer := common.HexToAddress("0x0000000000000000000000000000000000000001")
extraData := make([]byte, 0, utils.ExtraVanity+common.AddressLength+utils.ExtraSeal)
extraData = append(extraData, make([]byte, utils.ExtraVanity)...)
extraData = append(extraData, signer.Bytes()...)
extraData = append(extraData, make([]byte, utils.ExtraSeal)...)
genesis := &core.Genesis{
Config: config,
GasLimit: params.XDCGenesisGasLimit,
Difficulty: big.NewInt(1),
Alloc: types.GenesisAlloc{},
ExtraData: extraData,
}
db := rawdb.NewMemoryDatabase()
if _, err := genesis.Commit(db); err != nil {
t.Fatalf("failed to commit genesis: %v", err)
}
engine := ethash.NewFaker()
chain, err := core.NewBlockChain(db, nil, genesis, engine, vm.Config{})
if err != nil {
t.Fatalf("failed to create blockchain: %v", err)
}
defer chain.Stop()
worker := &worker{
chainConfig: config,
engine: engine,
chain: chain,
announceTxs: true,
}
parent, shouldReturn := worker.checkPreCommitWithLock()
if parent == nil {
t.Fatal("expected parent block, got nil")
}
if !shouldReturn {
t.Fatal("expected checkPreCommitWithLock to skip when XDPoS config is enabled but engine is not XDPoS")
}
if parent.Number().Sign() != 0 {
t.Fatalf("expected genesis parent, got number %v", parent.Number())
}
}
func TestWorkerSetGasTipValidation(t *testing.T) {
w := &worker{tip: uint256.NewInt(1)}
old := new(uint256.Int).Set(w.tip)
tests := []struct {
name string
tip *big.Int
}{
{name: "nil", tip: nil},
{name: "negative", tip: big.NewInt(-1)},
{name: "too high", tip: new(big.Int).Add(maxGasTip, big.NewInt(1))},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
if err := w.setGasTip(tc.tip); err == nil {
t.Fatalf("expected error for %s tip", tc.name)
}
if w.tip.Cmp(old) != 0 {
t.Fatalf("tip changed on invalid input: have %v want %v", w.tip, old)
}
})
}
}
func TestWorkerSetGasTipCopiesValue(t *testing.T) {
w := &worker{}
input := big.NewInt(2 * params.GWei)
if err := w.setGasTip(input); err != nil {
t.Fatalf("setGasTip failed: %v", err)
}
if w.tip == nil {
t.Fatal("worker tip was not set")
}
input.Add(input, big.NewInt(1))
if w.tip.Cmp(uint256.NewInt(2*params.GWei)) != 0 {
t.Fatalf("worker tip mutated via input pointer: have %v", w.tip)
}
}