Skip to content

Commit a5d08c8

Browse files
zsfelfoldifjl
authored andcommitted
les: code refactoring (ethereum#14416)
This commit does various code refactorings: - generalizes and moves the request retrieval/timeout/resend logic out of LesOdr (will be used by a subsequent PR) - reworks the peer management logic so that all services can register with peerSet to get notified about added/dropped peers (also gets rid of the ugly getAllPeers callback in requestDistributor) - moves peerSet, LesOdr, requestDistributor and retrieveManager initialization out of ProtocolManager because I believe they do not really belong there and the whole init process was ugly and ad-hoc
1 parent 60e27b5 commit a5d08c8

15 files changed

+699
-441
lines changed

les/backend.go

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package les
1919

2020
import (
2121
"fmt"
22+
"sync"
2223
"time"
2324

2425
"github.com/ethereum/go-ethereum/accounts"
@@ -38,6 +39,7 @@ import (
3839
"github.com/ethereum/go-ethereum/log"
3940
"github.com/ethereum/go-ethereum/node"
4041
"github.com/ethereum/go-ethereum/p2p"
42+
"github.com/ethereum/go-ethereum/p2p/discv5"
4143
"github.com/ethereum/go-ethereum/params"
4244
rpc "github.com/ethereum/go-ethereum/rpc"
4345
)
@@ -49,9 +51,13 @@ type LightEthereum struct {
4951
// Channel for shutting down the service
5052
shutdownChan chan bool
5153
// Handlers
54+
peers *peerSet
5255
txPool *light.TxPool
5356
blockchain *light.LightChain
5457
protocolManager *ProtocolManager
58+
serverPool *serverPool
59+
reqDist *requestDistributor
60+
retriever *retrieveManager
5561
// DB interfaces
5662
chainDb ethdb.Database // Block chain database
5763

@@ -63,6 +69,9 @@ type LightEthereum struct {
6369

6470
networkId uint64
6571
netRPCService *ethapi.PublicNetAPI
72+
73+
quitSync chan struct{}
74+
wg sync.WaitGroup
6675
}
6776

6877
func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
@@ -76,20 +85,26 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
7685
}
7786
log.Info("Initialised chain configuration", "config", chainConfig)
7887

79-
odr := NewLesOdr(chainDb)
80-
relay := NewLesTxRelay()
88+
peers := newPeerSet()
89+
quitSync := make(chan struct{})
90+
8191
eth := &LightEthereum{
82-
odr: odr,
83-
relay: relay,
84-
chainDb: chainDb,
8592
chainConfig: chainConfig,
93+
chainDb: chainDb,
8694
eventMux: ctx.EventMux,
95+
peers: peers,
96+
reqDist: newRequestDistributor(peers, quitSync),
8797
accountManager: ctx.AccountManager,
8898
engine: eth.CreateConsensusEngine(ctx, config, chainConfig, chainDb),
8999
shutdownChan: make(chan bool),
90100
networkId: config.NetworkId,
91101
}
92-
if eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.engine, eth.eventMux); err != nil {
102+
103+
eth.relay = NewLesTxRelay(peers, eth.reqDist)
104+
eth.serverPool = newServerPool(chainDb, quitSync, &eth.wg)
105+
eth.retriever = newRetrieveManager(peers, eth.reqDist, eth.serverPool)
106+
eth.odr = NewLesOdr(chainDb, eth.retriever)
107+
if eth.blockchain, err = light.NewLightChain(eth.odr, eth.chainConfig, eth.engine, eth.eventMux); err != nil {
93108
return nil, err
94109
}
95110
// Rewind the chain in case of an incompatible config upgrade.
@@ -100,13 +115,9 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
100115
}
101116

102117
eth.txPool = light.NewTxPool(eth.chainConfig, eth.eventMux, eth.blockchain, eth.relay)
103-
lightSync := config.SyncMode == downloader.LightSync
104-
if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, lightSync, config.NetworkId, eth.eventMux, eth.engine, eth.blockchain, nil, chainDb, odr, relay); err != nil {
118+
if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, true, config.NetworkId, eth.eventMux, eth.engine, eth.peers, eth.blockchain, nil, chainDb, eth.odr, eth.relay, quitSync, &eth.wg); err != nil {
105119
return nil, err
106120
}
107-
relay.ps = eth.protocolManager.peers
108-
relay.reqDist = eth.protocolManager.reqDist
109-
110121
eth.ApiBackend = &LesApiBackend{eth, nil}
111122
gpoParams := config.GPO
112123
if gpoParams.Default == nil {
@@ -116,6 +127,10 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
116127
return eth, nil
117128
}
118129

130+
func lesTopic(genesisHash common.Hash) discv5.Topic {
131+
return discv5.Topic("LES@" + common.Bytes2Hex(genesisHash.Bytes()[0:8]))
132+
}
133+
119134
type LightDummyAPI struct{}
120135

121136
// Etherbase is the address that mining rewards will be send to
@@ -188,7 +203,8 @@ func (s *LightEthereum) Protocols() []p2p.Protocol {
188203
func (s *LightEthereum) Start(srvr *p2p.Server) error {
189204
log.Warn("Light client mode is an experimental feature")
190205
s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.networkId)
191-
s.protocolManager.Start(srvr)
206+
s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash()))
207+
s.protocolManager.Start()
192208
return nil
193209
}
194210

les/distributor.go

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ var ErrNoPeers = errors.New("no suitable peers available")
3434
type requestDistributor struct {
3535
reqQueue *list.List
3636
lastReqOrder uint64
37+
peers map[distPeer]struct{}
38+
peerLock sync.RWMutex
3739
stopChn, loopChn chan struct{}
3840
loopNextSent bool
3941
lock sync.Mutex
40-
41-
getAllPeers func() map[distPeer]struct{}
4242
}
4343

4444
// distPeer is an LES server peer interface for the request distributor.
@@ -71,15 +71,39 @@ type distReq struct {
7171
}
7272

7373
// newRequestDistributor creates a new request distributor
74-
func newRequestDistributor(getAllPeers func() map[distPeer]struct{}, stopChn chan struct{}) *requestDistributor {
75-
r := &requestDistributor{
76-
reqQueue: list.New(),
77-
loopChn: make(chan struct{}, 2),
78-
stopChn: stopChn,
79-
getAllPeers: getAllPeers,
74+
func newRequestDistributor(peers *peerSet, stopChn chan struct{}) *requestDistributor {
75+
d := &requestDistributor{
76+
reqQueue: list.New(),
77+
loopChn: make(chan struct{}, 2),
78+
stopChn: stopChn,
79+
peers: make(map[distPeer]struct{}),
80+
}
81+
if peers != nil {
82+
peers.notify(d)
8083
}
81-
go r.loop()
82-
return r
84+
go d.loop()
85+
return d
86+
}
87+
88+
// registerPeer implements peerSetNotify
89+
func (d *requestDistributor) registerPeer(p *peer) {
90+
d.peerLock.Lock()
91+
d.peers[p] = struct{}{}
92+
d.peerLock.Unlock()
93+
}
94+
95+
// unregisterPeer implements peerSetNotify
96+
func (d *requestDistributor) unregisterPeer(p *peer) {
97+
d.peerLock.Lock()
98+
delete(d.peers, p)
99+
d.peerLock.Unlock()
100+
}
101+
102+
// registerTestPeer adds a new test peer
103+
func (d *requestDistributor) registerTestPeer(p distPeer) {
104+
d.peerLock.Lock()
105+
d.peers[p] = struct{}{}
106+
d.peerLock.Unlock()
83107
}
84108

85109
// distMaxWait is the maximum waiting time after which further necessary waiting
@@ -152,8 +176,7 @@ func (sp selectPeerItem) Weight() int64 {
152176
// nextRequest returns the next possible request from any peer, along with the
153177
// associated peer and necessary waiting time
154178
func (d *requestDistributor) nextRequest() (distPeer, *distReq, time.Duration) {
155-
peers := d.getAllPeers()
156-
179+
checkedPeers := make(map[distPeer]struct{})
157180
elem := d.reqQueue.Front()
158181
var (
159182
bestPeer distPeer
@@ -162,11 +185,14 @@ func (d *requestDistributor) nextRequest() (distPeer, *distReq, time.Duration) {
162185
sel *weightedRandomSelect
163186
)
164187

165-
for (len(peers) > 0 || elem == d.reqQueue.Front()) && elem != nil {
188+
d.peerLock.RLock()
189+
defer d.peerLock.RUnlock()
190+
191+
for (len(d.peers) > 0 || elem == d.reqQueue.Front()) && elem != nil {
166192
req := elem.Value.(*distReq)
167193
canSend := false
168-
for peer, _ := range peers {
169-
if peer.canQueue() && req.canSend(peer) {
194+
for peer, _ := range d.peers {
195+
if _, ok := checkedPeers[peer]; !ok && peer.canQueue() && req.canSend(peer) {
170196
canSend = true
171197
cost := req.getCost(peer)
172198
wait, bufRemain := peer.waitBefore(cost)
@@ -182,7 +208,7 @@ func (d *requestDistributor) nextRequest() (distPeer, *distReq, time.Duration) {
182208
bestWait = wait
183209
}
184210
}
185-
delete(peers, peer)
211+
checkedPeers[peer] = struct{}{}
186212
}
187213
}
188214
next := elem.Next()

les/distributor_test.go

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,20 +122,14 @@ func testRequestDistributor(t *testing.T, resend bool) {
122122
stop := make(chan struct{})
123123
defer close(stop)
124124

125+
dist := newRequestDistributor(nil, stop)
125126
var peers [testDistPeerCount]*testDistPeer
126127
for i, _ := range peers {
127128
peers[i] = &testDistPeer{}
128129
go peers[i].worker(t, !resend, stop)
130+
dist.registerTestPeer(peers[i])
129131
}
130132

131-
dist := newRequestDistributor(func() map[distPeer]struct{} {
132-
m := make(map[distPeer]struct{})
133-
for _, peer := range peers {
134-
m[peer] = struct{}{}
135-
}
136-
return m
137-
}, stop)
138-
139133
var wg sync.WaitGroup
140134

141135
for i := 1; i <= testDistReqCount; i++ {

les/fetcher.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ func newLightFetcher(pm *ProtocolManager) *lightFetcher {
116116
syncDone: make(chan *peer),
117117
maxConfirmedTd: big.NewInt(0),
118118
}
119+
pm.peers.notify(f)
119120
go f.syncLoop()
120121
return f
121122
}
@@ -209,8 +210,8 @@ func (f *lightFetcher) syncLoop() {
209210
}
210211
}
211212

212-
// addPeer adds a new peer to the fetcher's peer set
213-
func (f *lightFetcher) addPeer(p *peer) {
213+
// registerPeer adds a new peer to the fetcher's peer set
214+
func (f *lightFetcher) registerPeer(p *peer) {
214215
p.lock.Lock()
215216
p.hasBlock = func(hash common.Hash, number uint64) bool {
216217
return f.peerHasBlock(p, hash, number)
@@ -223,8 +224,8 @@ func (f *lightFetcher) addPeer(p *peer) {
223224
f.peers[p] = &fetcherPeerInfo{nodeByHash: make(map[common.Hash]*fetcherTreeNode)}
224225
}
225226

226-
// removePeer removes a new peer from the fetcher's peer set
227-
func (f *lightFetcher) removePeer(p *peer) {
227+
// unregisterPeer removes a new peer from the fetcher's peer set
228+
func (f *lightFetcher) unregisterPeer(p *peer) {
228229
p.lock.Lock()
229230
p.hasBlock = nil
230231
p.lock.Unlock()
@@ -416,7 +417,7 @@ func (f *lightFetcher) nextRequest() (*distReq, uint64) {
416417
f.syncing = bestSyncing
417418

418419
var rq *distReq
419-
reqID := getNextReqID()
420+
reqID := genReqID()
420421
if f.syncing {
421422
rq = &distReq{
422423
getCost: func(dp distPeer) uint64 {

0 commit comments

Comments
 (0)