diff --git a/cmd/geth/config.go b/cmd/geth/config.go index ef26f250ea..0a63a02776 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -123,7 +123,6 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { } // Apply flags. - utils.SetULC(ctx, &cfg.Eth) utils.SetNodeConfig(ctx, &cfg.Node) stack, err := node.New(&cfg.Node) if err != nil { @@ -133,7 +132,6 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) { cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name) } - utils.SetShhConfig(ctx, stack, &cfg.Shh) utils.SetDashboardConfig(ctx, &cfg.Dashboard) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index fd8f294217..4d0dc14da0 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -90,10 +90,6 @@ var ( utils.TxPoolAccountQueueFlag, utils.TxPoolGlobalQueueFlag, utils.TxPoolLifetimeFlag, - utils.ULCModeConfigFlag, - utils.OnlyAnnounceModeFlag, - utils.ULCTrustedNodesFlag, - utils.ULCMinTrustedFractionFlag, utils.SyncModeFlag, utils.ExitWhenSyncedFlag, utils.GCModeFlag, @@ -102,6 +98,9 @@ var ( utils.LightBandwidthOutFlag, utils.LightPeersFlag, utils.LightKDFFlag, + utils.UltraLightServersFlag, + utils.UltraLightFractionFlag, + utils.UltraLightOnlyAnnounceFlag, utils.WhitelistFlag, utils.CacheFlag, utils.CacheDatabaseFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 58a3b87a46..08bd76778e 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -86,6 +86,9 @@ var AppHelpFlagGroups = []flagGroup{ utils.LightBandwidthInFlag, utils.LightBandwidthOutFlag, utils.LightPeersFlag, + utils.UltraLightServersFlag, + utils.UltraLightFractionFlag, + utils.UltraLightOnlyAnnounceFlag, utils.LightKDFFlag, utils.WhitelistFlag, }, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 9a92e21fe9..e381f9bbbf 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -19,7 +19,6 @@ package utils import ( "crypto/ecdsa" - "encoding/json" "errors" "fmt" "io/ioutil" @@ -100,7 +99,6 @@ func NewApp(gitCommit, gitDate, usage string) *cli.App { app := cli.NewApp() app.Name = filepath.Base(os.Args[0]) app.Author = "" - //app.Authors = nil app.Email = "" app.Version = params.VersionWithCommit(gitCommit, gitDate) app.Usage = usage @@ -176,21 +174,19 @@ var ( Name: "exitwhensynced", Usage: "Exits after block synchronisation completes", } - ULCModeConfigFlag = cli.StringFlag{ - Name: "ulc.config", - Usage: "Config file to use for ultra light client mode", + UltraLightServersFlag = cli.StringFlag{ + Name: "ulc.servers", + Usage: "List of trusted ultra-light servers", + Value: strings.Join(eth.DefaultConfig.UltraLightServers, ","), } - OnlyAnnounceModeFlag = cli.BoolFlag{ - Name: "ulc.onlyannounce", - Usage: "ULC server sends announcements only", - } - ULCMinTrustedFractionFlag = cli.IntFlag{ + UltraLightFractionFlag = cli.IntFlag{ Name: "ulc.fraction", - Usage: "Minimum % of trusted ULC servers required to announce a new head", + Usage: "Minimum % of trusted ultra-light servers required to announce a new head", + Value: eth.DefaultConfig.UltraLightFraction, } - ULCTrustedNodesFlag = cli.StringFlag{ - Name: "ulc.trusted", - Usage: "List of trusted ULC servers", + UltraLightOnlyAnnounceFlag = cli.BoolFlag{ + Name: "ulc.onlyannounce", + Usage: "Ultra light server sends announcements only", } IterativeOutputFlag = cli.BoolFlag{ Name: "iterative", @@ -953,37 +949,20 @@ func setIPC(ctx *cli.Context, cfg *node.Config) { } } -// SetULC setup ULC config from file if given. -func SetULC(ctx *cli.Context, cfg *eth.Config) { - // ULC config isn't loaded from global config and ULC config and ULC trusted nodes are not defined. - if cfg.ULC == nil && !(ctx.GlobalIsSet(ULCModeConfigFlag.Name) || ctx.GlobalIsSet(ULCTrustedNodesFlag.Name)) { - return - } - cfg.ULC = ð.ULCConfig{} - - path := ctx.GlobalString(ULCModeConfigFlag.Name) - if path != "" { - cfgData, err := ioutil.ReadFile(path) - if err != nil { - Fatalf("Failed to unmarshal ULC configuration: %v", err) - } - - err = json.Unmarshal(cfgData, &cfg.ULC) - if err != nil { - Fatalf("Failed to unmarshal ULC configuration: %s", err.Error()) - } +// setUltraLight configures the ultra light client settings from the command line flags. +func setUltraLight(ctx *cli.Context, cfg *eth.Config) { + if ctx.GlobalIsSet(UltraLightServersFlag.Name) { + cfg.UltraLightServers = strings.Split(ctx.GlobalString(UltraLightServersFlag.Name), ",") } - - if trustedNodes := ctx.GlobalString(ULCTrustedNodesFlag.Name); trustedNodes != "" { - cfg.ULC.TrustedServers = strings.Split(trustedNodes, ",") + if ctx.GlobalIsSet(UltraLightFractionFlag.Name) { + cfg.UltraLightFraction = ctx.GlobalInt(UltraLightFractionFlag.Name) } - - if trustedFraction := ctx.GlobalInt(ULCMinTrustedFractionFlag.Name); trustedFraction > 0 { - cfg.ULC.MinTrustedFraction = trustedFraction + if cfg.UltraLightFraction <= 0 && cfg.UltraLightFraction > 100 { + log.Error("Ultra light fraction is invalid", "had", cfg.UltraLightFraction, "updated", eth.DefaultConfig.UltraLightFraction) + cfg.UltraLightFraction = eth.DefaultConfig.UltraLightFraction } - if cfg.ULC.MinTrustedFraction <= 0 && cfg.ULC.MinTrustedFraction > 100 { - log.Error("MinTrustedFraction is invalid", "MinTrustedFraction", cfg.ULC.MinTrustedFraction, "Changed to default", eth.DefaultULCMinTrustedFraction) - cfg.ULC.MinTrustedFraction = eth.DefaultULCMinTrustedFraction + if ctx.GlobalIsSet(UltraLightOnlyAnnounceFlag.Name) { + cfg.UltraLightOnlyAnnounce = ctx.GlobalBool(UltraLightOnlyAnnounceFlag.Name) } } @@ -1400,6 +1379,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { setEthash(ctx, cfg) setMiner(ctx, &cfg.Miner) setWhitelist(ctx, cfg) + setUltraLight(ctx, cfg) if ctx.GlobalIsSet(SyncModeFlag.Name) { cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) @@ -1412,9 +1392,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { if ctx.GlobalIsSet(LightPeersFlag.Name) { cfg.LightPeers = ctx.GlobalInt(LightPeersFlag.Name) } - if ctx.GlobalIsSet(OnlyAnnounceModeFlag.Name) { - cfg.OnlyAnnounce = ctx.GlobalBool(OnlyAnnounceModeFlag.Name) - } if ctx.GlobalIsSet(NetworkIdFlag.Name) { cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name) } diff --git a/eth/config.go b/eth/config.go index a5913442d8..8568f289ab 100644 --- a/eth/config.go +++ b/eth/config.go @@ -43,12 +43,13 @@ var DefaultConfig = Config{ DatasetsInMem: 1, DatasetsOnDisk: 2, }, - NetworkId: 1, - LightPeers: 100, - DatabaseCache: 512, - TrieCleanCache: 256, - TrieDirtyCache: 256, - TrieTimeout: 60 * time.Minute, + NetworkId: 1, + LightPeers: 100, + UltraLightFraction: 75, + DatabaseCache: 512, + TrieCleanCache: 256, + TrieDirtyCache: 256, + TrieTimeout: 60 * time.Minute, Miner: miner.Config{ GasFloor: 8000000, GasCeil: 8000000, @@ -101,14 +102,15 @@ type Config struct { Whitelist map[uint64]common.Hash `toml:"-"` // Light client options - LightServ int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests - LightBandwidthIn int `toml:",omitempty"` // Incoming bandwidth limit for light servers - LightBandwidthOut int `toml:",omitempty"` // Outgoing bandwidth limit for light servers - LightPeers int `toml:",omitempty"` // Maximum number of LES client peers - OnlyAnnounce bool // Maximum number of LES client peers + LightServ int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests + LightBandwidthIn int `toml:",omitempty"` // Incoming bandwidth limit for light servers + LightBandwidthOut int `toml:",omitempty"` // Outgoing bandwidth limit for light servers + LightPeers int `toml:",omitempty"` // Maximum number of LES client peers // Ultra Light client options - ULC *ULCConfig `toml:",omitempty"` + UltraLightServers []string `toml:",omitempty"` // List of trusted ultra light servers + UltraLightFraction int `toml:",omitempty"` // Percentage of trusted servers to accept an announcement + UltraLightOnlyAnnounce bool `toml:",omitempty"` // Whether to only announce headers, or also serve them // Database options SkipBcVersionCheck bool `toml:"-"` diff --git a/eth/gen_config.go b/eth/gen_config.go index d76499943d..f0ffb5a811 100644 --- a/eth/gen_config.go +++ b/eth/gen_config.go @@ -28,10 +28,11 @@ func (c Config) MarshalTOML() (interface{}, error) { LightBandwidthIn int `toml:",omitempty"` LightBandwidthOut int `toml:",omitempty"` LightPeers int `toml:",omitempty"` - OnlyAnnounce bool - ULC *ULCConfig `toml:",omitempty"` - SkipBcVersionCheck bool `toml:"-"` - DatabaseHandles int `toml:"-"` + UltraLightServers []string `toml:",omitempty"` + UltraLightFraction int `toml:",omitempty"` + UltraLightOnlyAnnounce bool `toml:",omitempty"` + SkipBcVersionCheck bool `toml:"-"` + DatabaseHandles int `toml:"-"` DatabaseCache int DatabaseFreezer string TrieCleanCache int @@ -45,7 +46,6 @@ func (c Config) MarshalTOML() (interface{}, error) { DocRoot string `toml:"-"` EWASMInterpreter string EVMInterpreter string - ConstantinopleOverride *big.Int RPCGasCap *big.Int `toml:",omitempty"` Checkpoint *params.TrustedCheckpoint CheckpointOracle *params.CheckpointOracleConfig @@ -61,8 +61,9 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.LightBandwidthIn = c.LightBandwidthIn enc.LightBandwidthOut = c.LightBandwidthOut enc.LightPeers = c.LightPeers - enc.OnlyAnnounce = c.OnlyAnnounce - enc.ULC = c.ULC + enc.UltraLightServers = c.UltraLightServers + enc.UltraLightFraction = c.UltraLightFraction + enc.UltraLightOnlyAnnounce = c.UltraLightOnlyAnnounce enc.SkipBcVersionCheck = c.SkipBcVersionCheck enc.DatabaseHandles = c.DatabaseHandles enc.DatabaseCache = c.DatabaseCache @@ -97,10 +98,11 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { LightBandwidthIn *int `toml:",omitempty"` LightBandwidthOut *int `toml:",omitempty"` LightPeers *int `toml:",omitempty"` - OnlyAnnounce *bool - ULC *ULCConfig `toml:",omitempty"` - SkipBcVersionCheck *bool `toml:"-"` - DatabaseHandles *int `toml:"-"` + UltraLightServers []string `toml:",omitempty"` + UltraLightFraction *int `toml:",omitempty"` + UltraLightOnlyAnnounce *bool `toml:",omitempty"` + SkipBcVersionCheck *bool `toml:"-"` + DatabaseHandles *int `toml:"-"` DatabaseCache *int DatabaseFreezer *string TrieCleanCache *int @@ -152,11 +154,14 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.LightPeers != nil { c.LightPeers = *dec.LightPeers } - if dec.OnlyAnnounce != nil { - c.OnlyAnnounce = *dec.OnlyAnnounce + if dec.UltraLightServers != nil { + c.UltraLightServers = dec.UltraLightServers } - if dec.ULC != nil { - c.ULC = dec.ULC + if dec.UltraLightFraction != nil { + c.UltraLightFraction = *dec.UltraLightFraction + } + if dec.UltraLightOnlyAnnounce != nil { + c.UltraLightOnlyAnnounce = *dec.UltraLightOnlyAnnounce } if dec.SkipBcVersionCheck != nil { c.SkipBcVersionCheck = *dec.SkipBcVersionCheck diff --git a/eth/ulc_config.go b/eth/ulc_config.go deleted file mode 100644 index effa6da217..0000000000 --- a/eth/ulc_config.go +++ /dev/null @@ -1,9 +0,0 @@ -package eth - -const DefaultULCMinTrustedFraction = 75 - -// ULCConfig is a Ultra Light client options. -type ULCConfig struct { - TrustedServers []string `toml:",omitempty"` // A list of trusted servers - MinTrustedFraction int `toml:",omitempty"` // Minimum percentage of connected trusted servers to validate trusted (1-100) -} diff --git a/les/backend.go b/les/backend.go index daaa6c71d9..c067afaea6 100644 --- a/les/backend.go +++ b/les/backend.go @@ -110,12 +110,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { bloomRequests: make(chan chan *bloombits.Retrieval), bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), } - - var trustedNodes []string - if leth.config.ULC != nil { - trustedNodes = leth.config.ULC.TrustedServers - } - leth.serverPool = newServerPool(chainDb, quitSync, &leth.wg, trustedNodes) + leth.serverPool = newServerPool(chainDb, quitSync, &leth.wg, leth.config.UltraLightServers) leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool) leth.relay = newLesTxRelay(peers, leth.retriever) @@ -159,11 +154,11 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { oracle = params.CheckpointOracles[genesisHash] } registrar := newCheckpointOracle(oracle, leth.getLocalCheckpoint) - if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, checkpoint, light.DefaultClientIndexerConfig, config.ULC, true, config.NetworkId, leth.eventMux, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.serverPool, registrar, quitSync, &leth.wg, nil); err != nil { + if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, checkpoint, light.DefaultClientIndexerConfig, config.UltraLightServers, config.UltraLightFraction, true, config.NetworkId, leth.eventMux, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.serverPool, registrar, quitSync, &leth.wg, nil); err != nil { return nil, err } - if leth.protocolManager.isULCEnabled() { - log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.protocolManager.ulc.trustedKeys), "minTrustedFraction", leth.protocolManager.ulc.minTrustedFraction) + if leth.protocolManager.ulc != nil { + log.Warn("Ultra light client is enabled", "servers", len(config.UltraLightServers), "fraction", config.UltraLightFraction) leth.blockchain.DisableCheckFreq() } return leth, nil diff --git a/les/fetcher.go b/les/fetcher.go index fa02be9a20..76e4f076a7 100644 --- a/les/fetcher.go +++ b/les/fetcher.go @@ -469,23 +469,18 @@ func (f *lightFetcher) findBestRequest() (bestHash common.Hash, bestAmount uint6 // isTrustedHash checks if the block can be trusted by the minimum trusted fraction. func (f *lightFetcher) isTrustedHash(hash common.Hash) bool { - if !f.pm.isULCEnabled() { + // If ultra light cliet mode is disabled, trust all hashes + if f.pm.ulc == nil { return true } - - var numAgreed int - for p, fp := range f.peers { - if !p.isTrusted { - continue + // Ultra light enabled, only trust after enough confirmations + var agreed int + for peer, info := range f.peers { + if peer.trusted && info.nodeByHash[hash] != nil { + agreed++ } - if _, ok := fp.nodeByHash[hash]; !ok { - continue - } - - numAgreed++ } - - return 100*numAgreed/len(f.pm.ulc.trustedKeys) >= f.pm.ulc.minTrustedFraction + return 100*agreed/len(f.pm.ulc.keys) >= f.pm.ulc.fraction } func (f *lightFetcher) newFetcherDistReqForSync(bestHash common.Hash) *distReq { @@ -498,16 +493,15 @@ func (f *lightFetcher) newFetcherDistReqForSync(bestHash common.Hash) *distReq { f.lock.Lock() defer f.lock.Unlock() - if p.isOnlyAnnounce { + if p.onlyAnnounce { return false } - fp := f.peers[p] return fp != nil && fp.nodeByHash[bestHash] != nil }, request: func(dp distPeer) func() { - if f.pm.isULCEnabled() { - //keep last trusted header before sync + if f.pm.ulc != nil { + // Keep last trusted header before sync f.setLastTrustedHeader(f.chain.CurrentHeader()) } go func() { @@ -533,10 +527,9 @@ func (f *lightFetcher) newFetcherDistReq(bestHash common.Hash, reqID uint64, bes f.lock.Lock() defer f.lock.Unlock() - if p.isOnlyAnnounce { + if p.onlyAnnounce { return false } - fp := f.peers[p] if fp == nil { return false @@ -708,36 +701,30 @@ func (f *lightFetcher) checkSyncedHeaders(p *peer) { p.Log().Debug("Unknown peer to check sync headers") return } - - n := fp.lastAnnounced - var td *big.Int - - var h *types.Header - if f.pm.isULCEnabled() { - var unapprovedHashes []common.Hash - // Overwrite last announced for ULC mode - h, unapprovedHashes = f.lastTrustedTreeNode(p) - //rollback untrusted blocks - f.chain.Rollback(unapprovedHashes) - //overwrite to last trusted - n = fp.nodeByHash[h.Hash()] - } - - //find last valid block - for n != nil { - if td = f.chain.GetTd(n.hash, n.number); td != nil { + var ( + node = fp.lastAnnounced + td *big.Int + ) + if f.pm.ulc != nil { + // Roll back untrusted blocks + h, unapproved := f.lastTrustedTreeNode(p) + f.chain.Rollback(unapproved) + node = fp.nodeByHash[h.Hash()] + } + // Find last valid block + for node != nil { + if td = f.chain.GetTd(node.hash, node.number); td != nil { break } - n = n.parent + node = node.parent } - - // Now n is the latest downloaded/approved header after syncing - if n == nil { + // Now node is the latest downloaded/approved header after syncing + if node == nil { p.Log().Debug("Synchronisation failed") go f.pm.removePeer(p.id) return } - header := f.chain.GetHeader(n.hash, n.number) + header := f.chain.GetHeader(node.hash, node.number) f.newHeaders([]*types.Header{header}, []*big.Int{td}) } diff --git a/les/fetcher_test.go b/les/fetcher_test.go index cc678c8c13..2ac72ddf78 100644 --- a/les/fetcher_test.go +++ b/les/fetcher_test.go @@ -36,22 +36,22 @@ func TestFetcherULCPeerSelector(t *testing.T) { lf := lightFetcher{ pm: &ProtocolManager{ ulc: &ulc{ - trustedKeys: map[string]struct{}{ - id1.String(): {}, - id2.String(): {}, - id3.String(): {}, - id4.String(): {}, + keys: map[string]bool{ + id1.String(): true, + id2.String(): true, + id3.String(): true, + id4.String(): true, }, - minTrustedFraction: 70, + fraction: 70, }, }, maxConfirmedTd: ftn1.td, peers: map[*peer]*fetcherPeerInfo{ { - id: "peer1", - Peer: p2p.NewPeer(id1, "peer1", []p2p.Cap{}), - isTrusted: true, + id: "peer1", + Peer: p2p.NewPeer(id1, "peer1", []p2p.Cap{}), + trusted: true, }: { nodeByHash: map[common.Hash]*fetcherTreeNode{ ftn1.hash: ftn1, @@ -59,9 +59,9 @@ func TestFetcherULCPeerSelector(t *testing.T) { }, }, { - Peer: p2p.NewPeer(id2, "peer2", []p2p.Cap{}), - id: "peer2", - isTrusted: true, + Peer: p2p.NewPeer(id2, "peer2", []p2p.Cap{}), + id: "peer2", + trusted: true, }: { nodeByHash: map[common.Hash]*fetcherTreeNode{ ftn1.hash: ftn1, @@ -69,9 +69,9 @@ func TestFetcherULCPeerSelector(t *testing.T) { }, }, { - id: "peer3", - Peer: p2p.NewPeer(id3, "peer3", []p2p.Cap{}), - isTrusted: true, + id: "peer3", + Peer: p2p.NewPeer(id3, "peer3", []p2p.Cap{}), + trusted: true, }: { nodeByHash: map[common.Hash]*fetcherTreeNode{ ftn1.hash: ftn1, @@ -80,9 +80,9 @@ func TestFetcherULCPeerSelector(t *testing.T) { }, }, { - id: "peer4", - Peer: p2p.NewPeer(id4, "peer4", []p2p.Cap{}), - isTrusted: true, + id: "peer4", + Peer: p2p.NewPeer(id4, "peer4", []p2p.Cap{}), + trusted: true, }: { nodeByHash: map[common.Hash]*fetcherTreeNode{ ftn1.hash: ftn1, diff --git a/les/handler.go b/les/handler.go index ea2ec33247..743776bd04 100644 --- a/les/handler.go +++ b/les/handler.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -130,7 +129,7 @@ type ProtocolManager struct { // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable // with the ethereum network. -func NewProtocolManager(chainConfig *params.ChainConfig, checkpoint *params.TrustedCheckpoint, indexerConfig *light.IndexerConfig, ulcConfig *eth.ULCConfig, client bool, networkId uint64, mux *event.TypeMux, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, serverPool *serverPool, registrar *checkpointOracle, quitSync chan struct{}, wg *sync.WaitGroup, synced func() bool) (*ProtocolManager, error) { +func NewProtocolManager(chainConfig *params.ChainConfig, checkpoint *params.TrustedCheckpoint, indexerConfig *light.IndexerConfig, ulcServers []string, ulcFraction int, client bool, networkId uint64, mux *event.TypeMux, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, serverPool *serverPool, registrar *checkpointOracle, quitSync chan struct{}, wg *sync.WaitGroup, synced func() bool) (*ProtocolManager, error) { // Create the protocol manager with the base fields manager := &ProtocolManager{ client: client, @@ -157,10 +156,14 @@ func NewProtocolManager(chainConfig *params.ChainConfig, checkpoint *params.Trus manager.reqDist = odr.retriever.dist } - if ulcConfig != nil { - manager.ulc = newULC(ulcConfig) + if ulcServers != nil { + ulc, err := newULC(ulcServers, ulcFraction) + if err != nil { + log.Warn("Failed to initialize ultra light client", "err", err) + } else { + manager.ulc = ulc + } } - removePeer := manager.removePeer if disableClientRemovePeer { removePeer = func(id string) {} @@ -247,11 +250,11 @@ func (pm *ProtocolManager) runPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWrit } func (pm *ProtocolManager) newPeer(pv int, nv uint64, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { - var isTrusted bool - if pm.isULCEnabled() { - isTrusted = pm.ulc.isTrusted(p.ID()) + var trusted bool + if pm.ulc != nil { + trusted = pm.ulc.trusted(p.ID()) } - return newPeer(pv, nv, isTrusted, p, newMeteredMsgWriter(rw)) + return newPeer(pv, nv, trusted, p, newMeteredMsgWriter(rw)) } // handle is the callback invoked to manage the life cycle of a les peer. When @@ -1197,14 +1200,6 @@ func (pm *ProtocolManager) txStatus(hash common.Hash) light.TxStatus { return stat } -// isULCEnabled returns true if we can use ULC -func (pm *ProtocolManager) isULCEnabled() bool { - if pm.ulc == nil || len(pm.ulc.trustedKeys) == 0 { - return false - } - return true -} - // downloaderPeerNotify implements peerSetNotify type downloaderPeerNotify ProtocolManager diff --git a/les/handler_test.go b/les/handler_test.go index e48db216a3..4e16a89791 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -588,7 +588,7 @@ func TestStopResumeLes3(t *testing.T) { db := rawdb.NewMemoryDatabase() clock := &mclock.Simulated{} testCost := testBufLimit / 10 - pm, _, err := newTestProtocolManager(false, 0, nil, nil, nil, db, nil, testCost, clock) + pm, _, err := newTestProtocolManager(false, 0, nil, nil, nil, db, nil, 0, testCost, clock) if err != nil { t.Fatalf("Failed to create protocol manager: %v", err) } diff --git a/les/helper_test.go b/les/helper_test.go index fd5236a99e..4b9f270cc7 100644 --- a/les/helper_test.go +++ b/les/helper_test.go @@ -167,7 +167,7 @@ func testIndexers(db ethdb.Database, odr light.OdrBackend, config *light.Indexer // newTestProtocolManager creates a new protocol manager for testing purposes, // with the given number of blocks already known, potential notification // channels for different events and relative chain indexers array. -func newTestProtocolManager(lightSync bool, blocks int, odr *LesOdr, indexers []*core.ChainIndexer, peers *peerSet, db ethdb.Database, ulcConfig *eth.ULCConfig, testCost uint64, clock mclock.Clock) (*ProtocolManager, *backends.SimulatedBackend, error) { +func newTestProtocolManager(lightSync bool, blocks int, odr *LesOdr, indexers []*core.ChainIndexer, peers *peerSet, db ethdb.Database, ulcServers []string, ulcFraction int, testCost uint64, clock mclock.Clock) (*ProtocolManager, *backends.SimulatedBackend, error) { var ( evmux = new(event.TypeMux) engine = ethash.NewFaker() @@ -219,7 +219,7 @@ func newTestProtocolManager(lightSync bool, blocks int, odr *LesOdr, indexers [] } reg = newCheckpointOracle(config, getLocal) } - pm, err := NewProtocolManager(gspec.Config, nil, indexConfig, ulcConfig, lightSync, NetworkId, evmux, peers, chain, pool, db, odr, nil, reg, exitCh, new(sync.WaitGroup), func() bool { return true }) + pm, err := NewProtocolManager(gspec.Config, nil, indexConfig, ulcServers, ulcFraction, lightSync, NetworkId, evmux, peers, chain, pool, db, odr, nil, reg, exitCh, new(sync.WaitGroup), func() bool { return true }) if err != nil { return nil, nil, err } @@ -249,8 +249,8 @@ func newTestProtocolManager(lightSync bool, blocks int, odr *LesOdr, indexers [] // with the given number of blocks already known, potential notification channels // for different events and relative chain indexers array. In case of an error, the // constructor force-fails the test. -func newTestProtocolManagerMust(t *testing.T, lightSync bool, blocks int, odr *LesOdr, indexers []*core.ChainIndexer, peers *peerSet, db ethdb.Database, ulcConfig *eth.ULCConfig) (*ProtocolManager, *backends.SimulatedBackend) { - pm, backend, err := newTestProtocolManager(lightSync, blocks, odr, indexers, peers, db, ulcConfig, 0, &mclock.System{}) +func newTestProtocolManagerMust(t *testing.T, lightSync bool, blocks int, odr *LesOdr, indexers []*core.ChainIndexer, peers *peerSet, db ethdb.Database, ulcServers []string, ulcFraction int) (*ProtocolManager, *backends.SimulatedBackend) { + pm, backend, err := newTestProtocolManager(lightSync, blocks, odr, indexers, peers, db, ulcServers, ulcFraction, 0, &mclock.System{}) if err != nil { t.Fatalf("Failed to create protocol manager: %v", err) } @@ -395,7 +395,7 @@ func newServerEnv(t *testing.T, blocks int, protocol int, waitIndexers func(*cor db := rawdb.NewMemoryDatabase() indexers := testIndexers(db, nil, light.TestServerIndexerConfig) - pm, b := newTestProtocolManagerMust(t, false, blocks, nil, indexers, nil, db, nil) + pm, b := newTestProtocolManagerMust(t, false, blocks, nil, indexers, nil, db, nil, 0) peer, _ := newTestPeer(t, "peer", protocol, pm, true, 0) cIndexer, bIndexer, btIndexer := indexers[0], indexers[1], indexers[2] @@ -441,8 +441,8 @@ func newClientServerEnv(t *testing.T, blocks int, protocol int, waitIndexers fun odr.SetIndexers(lcIndexer, lbtIndexer, lbIndexer) - pm, b := newTestProtocolManagerMust(t, false, blocks, nil, indexers, peers, db, nil) - lpm, lb := newTestProtocolManagerMust(t, true, 0, odr, lIndexers, lPeers, ldb, nil) + pm, b := newTestProtocolManagerMust(t, false, blocks, nil, indexers, peers, db, nil, 0) + lpm, lb := newTestProtocolManagerMust(t, true, 0, odr, lIndexers, lPeers, ldb, nil, 0) startIndexers := func(clientMode bool, pm *ProtocolManager) { if clientMode { diff --git a/les/odr.go b/les/odr.go index 9176924cb8..a26c06680b 100644 --- a/les/odr.go +++ b/les/odr.go @@ -108,7 +108,7 @@ func (odr *LesOdr) Retrieve(ctx context.Context, req light.OdrRequest) (err erro }, canSend: func(dp distPeer) bool { p := dp.(*peer) - if !p.isOnlyAnnounce { + if !p.onlyAnnounce { return lreq.CanSend(p) } return false diff --git a/les/peer.go b/les/peer.go index 76900410e9..1aa1613b0e 100644 --- a/les/peer.go +++ b/les/peer.go @@ -110,21 +110,21 @@ type peer struct { fcParams flowcontrol.ServerParams fcCosts requestCostTable - isTrusted bool - isOnlyAnnounce bool + trusted bool + onlyAnnounce bool chainSince, chainRecent uint64 stateSince, stateRecent uint64 } -func newPeer(version int, network uint64, isTrusted bool, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { +func newPeer(version int, network uint64, trusted bool, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { return &peer{ - Peer: p, - rw: rw, - version: version, - network: network, - id: fmt.Sprintf("%x", p.ID().Bytes()), - isTrusted: isTrusted, - errCh: make(chan error, 1), + Peer: p, + rw: rw, + version: version, + network: network, + id: fmt.Sprintf("%x", p.ID().Bytes()), + trusted: trusted, + errCh: make(chan error, 1), } } @@ -591,7 +591,7 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis } else { //on client node p.announceType = announceTypeSimple - if p.isTrusted { + if p.trusted { p.announceType = announceTypeSigned } send = send.add("announceType", p.announceType) @@ -652,22 +652,22 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis } else { //mark OnlyAnnounce server if "serveHeaders", "serveChainSince", "serveStateSince" or "txRelay" fields don't exist if recv.get("serveChainSince", &p.chainSince) != nil { - p.isOnlyAnnounce = true + p.onlyAnnounce = true } if recv.get("serveRecentChain", &p.chainRecent) != nil { p.chainRecent = 0 } if recv.get("serveStateSince", &p.stateSince) != nil { - p.isOnlyAnnounce = true + p.onlyAnnounce = true } if recv.get("serveRecentState", &p.stateRecent) != nil { p.stateRecent = 0 } if recv.get("txRelay", nil) != nil { - p.isOnlyAnnounce = true + p.onlyAnnounce = true } - if p.isOnlyAnnounce && !p.isTrusted { + if p.onlyAnnounce && !p.trusted { return errResp(ErrUselessPeer, "peer cannot serve requests") } @@ -689,7 +689,7 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis recv.get("checkpoint/value", &p.checkpoint) recv.get("checkpoint/registerHeight", &p.checkpointNumber) - if !p.isOnlyAnnounce { + if !p.onlyAnnounce { for msgCode := range reqAvgTimeCost { if p.fcCosts[msgCode] == nil { return errResp(ErrUselessPeer, "peer does not support message %d", msgCode) diff --git a/les/peer_test.go b/les/peer_test.go index d5ce166945..85de7cded6 100644 --- a/les/peer_test.go +++ b/les/peer_test.go @@ -29,9 +29,9 @@ func TestPeerHandshakeSetAnnounceTypeToAnnounceTypeSignedForTrustedPeer(t *testi //peer to connect(on ulc side) p := peer{ - Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), - version: protocol_version, - isTrusted: true, + Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), + version: protocol_version, + trusted: true, rw: &rwStub{ WriteHook: func(recvList keyValueList) { //checking that ulc sends to peer allowedRequests=onlyAnnounceRequests and announceType = announceTypeSigned @@ -140,7 +140,7 @@ func TestPeerHandshakeDefaultAllRequests(t *testing.T) { t.Fatal(err) } - if p.isOnlyAnnounce { + if p.onlyAnnounce { t.Fatal("Incorrect announceType") } } @@ -196,8 +196,8 @@ func TestPeerHandshakeClientReceiveOnlyAnnounceRequestsHeaders(t *testing.T) { return l }, }, - network: test_networkid, - isTrusted: true, + network: test_networkid, + trusted: true, } err := p.Handshake(td, hash, headNum, genesis, nil) @@ -205,8 +205,8 @@ func TestPeerHandshakeClientReceiveOnlyAnnounceRequestsHeaders(t *testing.T) { t.Fatal(err) } - if !p.isOnlyAnnounce { - t.Fatal("isOnlyAnnounce must be true") + if !p.onlyAnnounce { + t.Fatal("onlyAnnounce must be true") } } diff --git a/les/server.go b/les/server.go index 86570aa54d..0795baf9fd 100644 --- a/les/server.go +++ b/les/server.go @@ -77,7 +77,7 @@ func NewLesServer(e *eth.Ethereum, config *eth.Config) (*LesServer, error) { archiveMode: e.ArchiveMode(), quitSync: quitSync, lesTopics: lesTopics, - onlyAnnounce: config.OnlyAnnounce, + onlyAnnounce: config.UltraLightOnlyAnnounce, } srv.costTracker, srv.minCapacity = newCostTracker(e.ChainDb(), config) @@ -103,7 +103,7 @@ func NewLesServer(e *eth.Ethereum, config *eth.Config) (*LesServer, error) { } registrar := newCheckpointOracle(oracle, srv.getLocalCheckpoint) // TODO(rjl493456442) Checkpoint is useless for les server, separate handler for client and server. - pm, err := NewProtocolManager(e.BlockChain().Config(), nil, light.DefaultServerIndexerConfig, config.ULC, false, config.NetworkId, e.EventMux(), newPeerSet(), e.BlockChain(), e.TxPool(), e.ChainDb(), nil, nil, registrar, quitSync, new(sync.WaitGroup), e.Synced) + pm, err := NewProtocolManager(e.BlockChain().Config(), nil, light.DefaultServerIndexerConfig, config.UltraLightServers, config.UltraLightFraction, false, config.NetworkId, e.EventMux(), newPeerSet(), e.BlockChain(), e.TxPool(), e.ChainDb(), nil, nil, registrar, quitSync, new(sync.WaitGroup), e.Synced) if err != nil { return nil, err } diff --git a/les/txrelay.go b/les/txrelay.go index ffbe251fc4..49195161b7 100644 --- a/les/txrelay.go +++ b/les/txrelay.go @@ -130,7 +130,7 @@ func (self *lesTxRelay) send(txs types.Transactions, count int) { return peer.GetTxRelayCost(len(ll), len(enc)) }, canSend: func(dp distPeer) bool { - return !dp.(*peer).isOnlyAnnounce && dp.(*peer) == pp + return !dp.(*peer).onlyAnnounce && dp.(*peer) == pp }, request: func(dp distPeer) func() { peer := dp.(*peer) diff --git a/les/ulc.go b/les/ulc.go index 8792f60d3c..b97217e796 100644 --- a/les/ulc.go +++ b/les/ulc.go @@ -17,38 +17,38 @@ package les import ( - "github.com/ethereum/go-ethereum/eth" + "errors" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" ) type ulc struct { - trustedKeys map[string]struct{} - minTrustedFraction int + keys map[string]bool + fraction 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 { +// newULC creates and returns an ultra light client instance. +func newULC(servers []string, fraction int) (*ulc, error) { + keys := make(map[string]bool) + for _, id := range servers { node, err := enode.Parse(enode.ValidSchemes, id) if err != nil { - log.Debug("Failed to parse trusted server", "id", id, "err", err) + log.Warn("Failed to parse trusted server", "id", id, "err", err) continue } - m[node.ID().String()] = struct{}{} + keys[node.ID().String()] = true } - return &ulc{m, ulcConfig.MinTrustedFraction} + if len(keys) == 0 { + return nil, errors.New("no trusted servers") + } + return &ulc{ + keys: keys, + fraction: fraction, + }, nil } -// 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 - } - _, ok := u.trustedKeys[p.String()] - return ok +// trusted return an indicator that whether the specified peer is trusted. +func (u *ulc) trusted(p enode.ID) bool { + return u.keys[p.String()] } diff --git a/les/ulc_test.go b/les/ulc_test.go index 3a3281a3f3..cd2bedae84 100644 --- a/les/ulc_test.go +++ b/les/ulc_test.go @@ -28,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" @@ -36,22 +35,15 @@ import ( func TestULCSyncWithOnePeer(t *testing.T) { f := newFullPeerPair(t, 1, 4) - ulcConfig := ð.ULCConfig{ - MinTrustedFraction: 100, - TrustedServers: []string{f.Node.String()}, - } - - l := newLightPeer(t, ulcConfig) + l := newLightPeer(t, []string{f.Node.String()}, 100) if reflect.DeepEqual(f.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) { t.Fatal("blocks are equal") } - _, _, err := connectPeers(f, l, 2) if err != nil { t.Fatal(err) } - l.PM.fetcher.lock.Lock() l.PM.fetcher.nextRequest() l.PM.fetcher.lock.Unlock() @@ -63,24 +55,17 @@ func TestULCSyncWithOnePeer(t *testing.T) { func TestULCReceiveAnnounce(t *testing.T) { f := newFullPeerPair(t, 1, 4) - ulcConfig := ð.ULCConfig{ - MinTrustedFraction: 100, - TrustedServers: []string{f.Node.String()}, - } - - l := newLightPeer(t, ulcConfig) + l := newLightPeer(t, []string{f.Node.String()}, 100) fPeer, lPeer, err := connectPeers(f, l, 2) if err != nil { t.Fatal(err) } - l.PM.synchronise(fPeer) //check that the sync is finished correctly if !reflect.DeepEqual(f.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) { t.Fatal("sync doesn't work") } - l.PM.peers.lock.Lock() if len(l.PM.peers.peers) == 0 { t.Fatal("peer list should not be empty") @@ -101,16 +86,7 @@ func TestULCReceiveAnnounce(t *testing.T) { func TestULCShouldNotSyncWithTwoPeersOneHaveEmptyChain(t *testing.T) { f1 := newFullPeerPair(t, 1, 4) f2 := newFullPeerPair(t, 2, 0) - ulcConf := &ulc{minTrustedFraction: 100, trustedKeys: make(map[string]struct{})} - ulcConf.trustedKeys[f1.Node.ID().String()] = struct{}{} - ulcConf.trustedKeys[f2.Node.ID().String()] = struct{}{} - ulcConfig := ð.ULCConfig{ - MinTrustedFraction: 100, - TrustedServers: []string{f1.Node.String(), f2.Node.String()}, - } - l := newLightPeer(t, ulcConfig) - l.PM.ulc.minTrustedFraction = 100 - + l := newLightPeer(t, []string{f1.Node.String(), f2.Node.String()}, 100) _, _, err := connectPeers(f1, l, 2) if err != nil { t.Fatal(err) @@ -119,7 +95,6 @@ func TestULCShouldNotSyncWithTwoPeersOneHaveEmptyChain(t *testing.T) { if err != nil { t.Fatal(err) } - l.PM.fetcher.lock.Lock() l.PM.fetcher.nextRequest() l.PM.fetcher.lock.Unlock() @@ -134,27 +109,19 @@ func TestULCShouldNotSyncWithThreePeersOneHaveEmptyChain(t *testing.T) { f2 := newFullPeerPair(t, 2, 4) f3 := newFullPeerPair(t, 3, 0) - ulcConfig := ð.ULCConfig{ - MinTrustedFraction: 60, - TrustedServers: []string{f1.Node.String(), f2.Node.String(), f3.Node.String()}, - } - - l := newLightPeer(t, ulcConfig) + l := newLightPeer(t, []string{f1.Node.String(), f2.Node.String(), f3.Node.String()}, 60) _, _, err := connectPeers(f1, l, 2) if err != nil { t.Fatal(err) } - _, _, err = connectPeers(f2, l, 2) if err != nil { t.Fatal(err) } - _, _, err = connectPeers(f3, l, 2) if err != nil { t.Fatal(err) } - l.PM.fetcher.lock.Lock() l.PM.fetcher.nextRequest() l.PM.fetcher.lock.Unlock() @@ -213,7 +180,7 @@ func connectPeers(full, light pairPeer, version int) (*peer, *peer, error) { func newFullPeerPair(t *testing.T, index int, numberOfblocks int) pairPeer { db := rawdb.NewMemoryDatabase() - pmFull, _ := newTestProtocolManagerMust(t, false, numberOfblocks, nil, nil, nil, db, nil) + pmFull, _ := newTestProtocolManagerMust(t, false, numberOfblocks, nil, nil, nil, db, nil, 0) peerPairFull := pairPeer{ Name: "full node", @@ -229,7 +196,7 @@ func newFullPeerPair(t *testing.T, index int, numberOfblocks int) pairPeer { } // newLightPeer creates node with light sync mode -func newLightPeer(t *testing.T, ulcConfig *eth.ULCConfig) pairPeer { +func newLightPeer(t *testing.T, ulcServers []string, ulcFraction int) pairPeer { peers := newPeerSet() dist := newRequestDistributor(peers, make(chan struct{}), &mclock.System{}) rm := newRetrieveManager(peers, dist, nil) @@ -237,12 +204,11 @@ func newLightPeer(t *testing.T, ulcConfig *eth.ULCConfig) pairPeer { odr := NewLesOdr(ldb, light.DefaultClientIndexerConfig, rm) - pmLight, _ := newTestProtocolManagerMust(t, true, 0, odr, nil, peers, ldb, ulcConfig) + pmLight, _ := newTestProtocolManagerMust(t, true, 0, odr, nil, peers, ldb, ulcServers, ulcFraction) peerPairLight := pairPeer{ Name: "ulc node", PM: pmLight, } - key, err := crypto.GenerateKey() if err != nil { t.Fatal("generate key err:", err) diff --git a/mobile/geth.go b/mobile/geth.go index fba3e5711b..edcbfdbdbe 100644 --- a/mobile/geth.go +++ b/mobile/geth.go @@ -76,9 +76,6 @@ type NodeConfig struct { // Listening address of pprof server. PprofAddress string - - // Ultra Light client options - ULC *eth.ULCConfig } // defaultNodeConfig contains the default node configuration values to use if all