diff --git a/eth/backend.go b/eth/backend.go index 6b9c98bf2..fbf4dd7bb 100644 --- a/eth/backend.go +++ b/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. diff --git a/les/backend.go b/les/backend.go index 887f88210..ed0f45057 100644 --- a/les/backend.go +++ b/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 } diff --git a/les/handler.go b/les/handler.go index 0d235e7a5..f53a4722f 100644 --- a/les/handler.go +++ b/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() diff --git a/les/helper_test.go b/les/helper_test.go index 9a302f837..878e44404 100644 --- a/les/helper_test.go +++ b/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 } diff --git a/les/server.go b/les/server.go index 6c2b227f4..6b93b846d 100644 --- a/les/server.go +++ b/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) diff --git a/les/transactions.rlp b/les/transactions.rlp new file mode 100755 index 000000000..e69de29bb diff --git a/les/ulc.go b/les/ulc.go index d9f7dc76c..c6d415552 100644 --- a/les/ulc.go +++ b/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 . + 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 diff --git a/les/ulc_test.go b/les/ulc_test.go index 81986fa1e..38adeb95f 100644 --- a/les/ulc_test.go +++ b/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 . + package les import (