Browse Source

eth, les: reject light client connection is server is not synced (#19616)

* eth, les: reject light client connection is server is not synced

* eth, les: rename function and variables

* les: format
gary rong 6 years ago
parent
commit
4e0c1a1a6b
8 changed files with 71 additions and 31 deletions
  1. 1 0
      eth/backend.go
  2. 2 1
      les/backend.go
  3. 29 23
      les/handler.go
  4. 1 1
      les/helper_test.go
  5. 2 1
      les/server.go
  6. 0 0
      les/transactions.rlp
  7. 20 5
      les/ulc.go
  8. 16 0
      les/ulc_test.go

+ 1 - 0
eth/backend.go

@@ -480,6 +480,7 @@ func (s *Ethereum) IsListening() bool                  { return true } // Always
 func (s *Ethereum) EthVersion() int                    { return int(s.protocolManager.SubProtocols[0].Version) }
 func (s *Ethereum) NetVersion() uint64                 { return s.networkID }
 func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
+func (s *Ethereum) Synced() bool                       { return atomic.LoadUint32(&s.protocolManager.acceptTxs) == 1 }
 
 // Protocols implements node.Service, returning all the currently configured
 // network protocols to start.

+ 2 - 1
les/backend.go

@@ -158,7 +158,8 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
 		leth.serverPool,
 		quitSync,
 		&leth.wg,
-		config.ULC); err != nil {
+		config.ULC,
+		nil); err != nil {
 		return nil, err
 	}
 

+ 29 - 23
les/handler.go

@@ -87,12 +87,16 @@ type txPool interface {
 }
 
 type ProtocolManager struct {
-	lightSync    bool
+	// Configs
+	chainConfig *params.ChainConfig
+	iConfig     *light.IndexerConfig
+
+	client    bool   // The indicator whether the node is light client
+	maxPeers  int    // The maximum number peers allowed to connect.
+	networkId uint64 // The identity of network.
+
 	txpool       txPool
 	txrelay      *LesTxRelay
-	networkId    uint64
-	chainConfig  *params.ChainConfig
-	iConfig      *light.IndexerConfig
 	blockchain   BlockChain
 	chainDb      ethdb.Database
 	odr          *LesOdr
@@ -102,23 +106,21 @@ type ProtocolManager struct {
 	reqDist      *requestDistributor
 	retriever    *retrieveManager
 	servingQueue *servingQueue
-
-	downloader *downloader.Downloader
-	fetcher    *lightFetcher
-	peers      *peerSet
-	maxPeers   int
-
-	eventMux *event.TypeMux
+	downloader   *downloader.Downloader
+	fetcher      *lightFetcher
+	ulc          *ulc
+	peers        *peerSet
 
 	// channels for fetcher, syncer, txsyncLoop
 	newPeerCh   chan *peer
 	quitSync    chan struct{}
 	noMorePeers chan struct{}
 
-	// wait group is used for graceful shutdowns during downloading
-	// and processing
-	wg  *sync.WaitGroup
-	ulc *ulc
+	wg       *sync.WaitGroup
+	eventMux *event.TypeMux
+
+	// Callbacks
+	synced func() bool
 }
 
 // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
@@ -126,7 +128,7 @@ type ProtocolManager struct {
 func NewProtocolManager(
 	chainConfig *params.ChainConfig,
 	indexerConfig *light.IndexerConfig,
-	lightSync bool,
+	client bool,
 	networkId uint64,
 	mux *event.TypeMux,
 	engine consensus.Engine,
@@ -139,10 +141,10 @@ func NewProtocolManager(
 	serverPool *serverPool,
 	quitSync chan struct{},
 	wg *sync.WaitGroup,
-	ulcConfig *eth.ULCConfig) (*ProtocolManager, error) {
+	ulcConfig *eth.ULCConfig, synced func() bool) (*ProtocolManager, error) {
 	// Create the protocol manager with the base fields
 	manager := &ProtocolManager{
-		lightSync:   lightSync,
+		client:      client,
 		eventMux:    mux,
 		blockchain:  blockchain,
 		chainConfig: chainConfig,
@@ -158,6 +160,7 @@ func NewProtocolManager(
 		quitSync:    quitSync,
 		wg:          wg,
 		noMorePeers: make(chan struct{}),
+		synced:      synced,
 	}
 	if odr != nil {
 		manager.retriever = odr.retriever
@@ -174,7 +177,7 @@ func NewProtocolManager(
 	if disableClientRemovePeer {
 		removePeer = func(id string) {}
 	}
-	if lightSync {
+	if client {
 		var checkpoint uint64
 		if cht, ok := params.TrustedCheckpoints[blockchain.Genesis().Hash()]; ok {
 			checkpoint = (cht.SectionIndex+1)*params.CHTFrequency - 1
@@ -193,7 +196,7 @@ func (pm *ProtocolManager) removePeer(id string) {
 
 func (pm *ProtocolManager) Start(maxPeers int) {
 	pm.maxPeers = maxPeers
-	if pm.lightSync {
+	if pm.client {
 		go pm.syncer()
 	} else {
 		go func() {
@@ -268,10 +271,13 @@ func (pm *ProtocolManager) newPeer(pv int, nv uint64, p *p2p.Peer, rw p2p.MsgRea
 func (pm *ProtocolManager) handle(p *peer) error {
 	// Ignore maxPeers if this is a trusted peer
 	// In server mode we try to check into the client pool after handshake
-	if pm.lightSync && pm.peers.Len() >= pm.maxPeers && !p.Peer.Info().Network.Trusted {
+	if pm.client && pm.peers.Len() >= pm.maxPeers && !p.Peer.Info().Network.Trusted {
 		return p2p.DiscTooManyPeers
 	}
-
+	// Reject light clients if server is not synced.
+	if !pm.client && !pm.synced() {
+		return p2p.DiscRequested
+	}
 	p.Log().Debug("Light Ethereum peer connected", "name", p.Name())
 
 	// Execute the LES handshake
@@ -304,7 +310,7 @@ func (pm *ProtocolManager) handle(p *peer) error {
 	}()
 
 	// Register the peer in the downloader. If the downloader considers it banned, we disconnect
-	if pm.lightSync {
+	if pm.client {
 		p.lock.Lock()
 		head := p.headInfo
 		p.lock.Unlock()

+ 1 - 1
les/helper_test.go

@@ -170,7 +170,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
 	if lightSync {
 		indexConfig = light.TestClientIndexerConfig
 	}
-	pm, err := NewProtocolManager(gspec.Config, indexConfig, lightSync, NetworkId, evmux, engine, peers, chain, pool, db, odr, nil, nil, make(chan struct{}), new(sync.WaitGroup), ulcConfig)
+	pm, err := NewProtocolManager(gspec.Config, indexConfig, lightSync, NetworkId, evmux, engine, peers, chain, pool, db, odr, nil, nil, make(chan struct{}), new(sync.WaitGroup), ulcConfig, func() bool { return true })
 	if err != nil {
 		return nil, err
 	}

+ 2 - 1
les/server.go

@@ -74,7 +74,7 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
 		nil,
 		quitSync,
 		new(sync.WaitGroup),
-		config.ULC)
+		config.ULC, eth.Synced)
 	if err != nil {
 		return nil, err
 	}
@@ -243,6 +243,7 @@ func (s *LesServer) Stop() {
 	s.protocolManager.Stop()
 }
 
+// todo(rjl493456442) separate client and server implementation.
 func (pm *ProtocolManager) blockLoop() {
 	pm.wg.Add(1)
 	headCh := make(chan core.ChainHeadEvent, 10)

+ 0 - 0
les/transactions.rlp


+ 20 - 5
les/ulc.go

@@ -1,9 +1,24 @@
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
 package les
 
 import (
-	"fmt"
-
 	"github.com/ethereum/go-ethereum/eth"
+	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/p2p/enode"
 )
 
@@ -12,24 +27,24 @@ type ulc struct {
 	minTrustedFraction int
 }
 
+// newULC creates and returns a ultra light client instance.
 func newULC(ulcConfig *eth.ULCConfig) *ulc {
 	if ulcConfig == nil {
 		return nil
 	}
-
 	m := make(map[string]struct{}, len(ulcConfig.TrustedServers))
 	for _, id := range ulcConfig.TrustedServers {
 		node, err := enode.ParseV4(id)
 		if err != nil {
-			fmt.Println("node:", id, " err:", err)
+			log.Debug("Failed to parse trusted server", "id", id, "err", err)
 			continue
 		}
 		m[node.ID().String()] = struct{}{}
 	}
-
 	return &ulc{m, ulcConfig.MinTrustedFraction}
 }
 
+// isTrusted return an indicator that whether the specified peer is trusted.
 func (u *ulc) isTrusted(p enode.ID) bool {
 	if u.trustedKeys == nil {
 		return false

+ 16 - 0
les/ulc_test.go

@@ -1,3 +1,19 @@
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
 package les
 
 import (