diff --git a/cmd/geth/config.go b/cmd/geth/config.go index e6bd4d5bef..b0749d2329 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -168,6 +168,9 @@ func makeFullNode(ctx *cli.Context) *node.Node { if ctx.GlobalIsSet(utils.WhisperMinPOWFlag.Name) { cfg.Shh.MinimumAcceptedPOW = ctx.Float64(utils.WhisperMinPOWFlag.Name) } + if ctx.GlobalIsSet(utils.WhisperRestrictConnectionBetweenLightClientsFlag.Name) { + cfg.Shh.RestrictConnectionBetweenLightClients = true + } utils.RegisterShhService(stack, &cfg.Shh) } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 09d9c493d1..27d901fe50 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -139,6 +139,7 @@ var ( utils.WhisperEnabledFlag, utils.WhisperMaxMessageSizeFlag, utils.WhisperMinPOWFlag, + utils.WhisperRestrictConnectionBetweenLightClientsFlag, } ) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ef5f6a9f08..46e1e33fe4 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -532,6 +532,10 @@ var ( Usage: "Minimum POW accepted", Value: whisper.DefaultMinimumPoW, } + WhisperRestrictConnectionBetweenLightClientsFlag = cli.BoolFlag{ + Name: "shh.restrict-light", + Usage: "Restrict connection between two whisper light clients", + } ) // MakeDataDir retrieves the currently requested data directory, terminating @@ -1007,6 +1011,9 @@ func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) { if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) { cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name) } + if ctx.GlobalIsSet(WhisperRestrictConnectionBetweenLightClientsFlag.Name) { + cfg.RestrictConnectionBetweenLightClients = true + } } // SetEthConfig applies eth-related command line flags to the config. diff --git a/whisper/whisperv6/config.go b/whisper/whisperv6/config.go index 61419de007..cb7d53f8aa 100644 --- a/whisper/whisperv6/config.go +++ b/whisper/whisperv6/config.go @@ -18,12 +18,14 @@ package whisperv6 // Config represents the configuration state of a whisper node. type Config struct { - MaxMessageSize uint32 `toml:",omitempty"` - MinimumAcceptedPOW float64 `toml:",omitempty"` + MaxMessageSize uint32 `toml:",omitempty"` + MinimumAcceptedPOW float64 `toml:",omitempty"` + RestrictConnectionBetweenLightClients bool `toml:",omitempty"` } // DefaultConfig represents (shocker!) the default configuration. var DefaultConfig = Config{ - MaxMessageSize: DefaultMaxMessageSize, - MinimumAcceptedPOW: DefaultMinimumPoW, + MaxMessageSize: DefaultMaxMessageSize, + MinimumAcceptedPOW: DefaultMinimumPoW, + RestrictConnectionBetweenLightClients: false, } diff --git a/whisper/whisperv6/peer.go b/whisper/whisperv6/peer.go index a662397c64..2f01dfb5a4 100644 --- a/whisper/whisperv6/peer.go +++ b/whisper/whisperv6/peer.go @@ -80,6 +80,7 @@ func (peer *Peer) handshake() error { // Send the handshake status message asynchronously errc := make(chan error, 1) isLightNode := peer.host.LightClientMode() + isRestrictedLightNodeConnection := peer.host.LightClientModeConnectionRestricted() go func() { pow := peer.host.MinPow() powConverted := math.Float64bits(pow) @@ -130,8 +131,8 @@ func (peer *Peer) handshake() error { } b, err := s.Bool() - if b && isLightNode { - return fmt.Errorf("peer [%x]: useless peer: two pure light node communication", peer.ID()) + if b && isLightNode && isRestrictedLightNodeConnection { + return fmt.Errorf("peer [%x] is useless: two pure light node communication restricted", peer.ID()) } if err := <-errc; err != nil { diff --git a/whisper/whisperv6/peer_test.go b/whisper/whisperv6/peer_test.go index 076b024b85..35d752baf4 100644 --- a/whisper/whisperv6/peer_test.go +++ b/whisper/whisperv6/peer_test.go @@ -514,7 +514,8 @@ func waitForServersToStart(t *testing.T) { t.Fatalf("Failed to start all the servers, running: %d", started) } -func TestPureLightPeerHandshake(t *testing.T) { +//two generic whisper node handshake +func TestPeerHandshakeWithTwoFullNode(t *testing.T) { w1 := Whisper{} p1 := newPeer(&w1, p2p.NewPeer(discover.NodeID{}, "test", []p2p.Cap{}), &rwStub{[]interface{}{ProtocolVersion, uint64(123), make([]byte, BloomFilterSize), false}}) err := p1.handshake() @@ -523,7 +524,8 @@ func TestPureLightPeerHandshake(t *testing.T) { } } -func TestPureLightPeerHandshakeWithOldVersion(t *testing.T) { +//two generic whisper node handshake. one don't send light flag +func TestHandshakeWithOldVersionWithoutLightModeFlag(t *testing.T) { w1 := Whisper{} p1 := newPeer(&w1, p2p.NewPeer(discover.NodeID{}, "test", []p2p.Cap{}), &rwStub{[]interface{}{ProtocolVersion, uint64(123), make([]byte, BloomFilterSize)}}) err := p1.handshake() @@ -532,8 +534,22 @@ func TestPureLightPeerHandshakeWithOldVersion(t *testing.T) { } } +//two light nodes handshake. restriction disabled +func TestPureLightPeerHandshakeRestrictionOff(t *testing.T) { + w1 := Whisper{} + w1.settings.Store(restrictConnectionBetweenLightClientsIdx, false) + w1.SetLightClientMode(true) + p1 := newPeer(&w1, p2p.NewPeer(discover.NodeID{}, "test", []p2p.Cap{}), &rwStub{[]interface{}{ProtocolVersion, uint64(123), make([]byte, BloomFilterSize), true}}) + err := p1.handshake() + if err != nil { + t.FailNow() + } +} + +//two light nodes handshake. restriction enabled func TestPureLightPeerHandshakeError(t *testing.T) { w1 := Whisper{} + w1.settings.Store(restrictConnectionBetweenLightClientsIdx, true) w1.SetLightClientMode(true) p1 := newPeer(&w1, p2p.NewPeer(discover.NodeID{}, "test", []p2p.Cap{}), &rwStub{[]interface{}{ProtocolVersion, uint64(123), make([]byte, BloomFilterSize), true}}) err := p1.handshake() diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go index 4384fed9ed..9c7611a16b 100644 --- a/whisper/whisperv6/whisper.go +++ b/whisper/whisperv6/whisper.go @@ -49,13 +49,14 @@ type Statistics struct { } const ( - maxMsgSizeIdx = iota // Maximal message length allowed by the whisper node - overflowIdx // Indicator of message queue overflow - minPowIdx // Minimal PoW required by the whisper node - minPowToleranceIdx // Minimal PoW tolerated by the whisper node for a limited time - bloomFilterIdx // Bloom filter for topics of interest for this node - bloomFilterToleranceIdx // Bloom filter tolerated by the whisper node for a limited time - lightClientModeIdx // Pure light client mode. (does not forward any messages) + maxMsgSizeIdx = iota // Maximal message length allowed by the whisper node + overflowIdx // Indicator of message queue overflow + minPowIdx // Minimal PoW required by the whisper node + minPowToleranceIdx // Minimal PoW tolerated by the whisper node for a limited time + bloomFilterIdx // Bloom filter for topics of interest for this node + bloomFilterToleranceIdx // Bloom filter tolerated by the whisper node for a limited time + lightClientModeIdx // Light client mode. (does not forward any messages) + restrictConnectionBetweenLightClientsIdx // Restrict connection between two light clients ) // Whisper represents a dark communication interface through the Ethereum @@ -112,6 +113,7 @@ func New(cfg *Config) *Whisper { whisper.settings.Store(minPowIdx, cfg.MinimumAcceptedPOW) whisper.settings.Store(maxMsgSizeIdx, cfg.MaxMessageSize) whisper.settings.Store(overflowIdx, false) + whisper.settings.Store(restrictConnectionBetweenLightClientsIdx, cfg.RestrictConnectionBetweenLightClients) // p2p whisper sub protocol handler whisper.protocol = p2p.Protocol{ @@ -275,12 +277,12 @@ func (whisper *Whisper) SetMinimumPowTest(val float64) { whisper.settings.Store(minPowToleranceIdx, val) } -//SetLightClientMode makes node pure light client (does not forward any messages) +//SetLightClientMode makes node light client (does not forward any messages) func (whisper *Whisper) SetLightClientMode(v bool) { whisper.settings.Store(lightClientModeIdx, v) } -//LightClientMode indicates is this node is pure light client (does not forward any messages) +//LightClientMode indicates is this node is light client (does not forward any messages) func (whisper *Whisper) LightClientMode() bool { val, exist := whisper.settings.Load(lightClientModeIdx) if !exist || val == nil { @@ -293,6 +295,19 @@ func (whisper *Whisper) LightClientMode() bool { return v } +//LightClientModeConnectionRestricted indicates that connection to light client in light client mode not allowed +func (whisper *Whisper) LightClientModeConnectionRestricted() bool { + val, exist := whisper.settings.Load(restrictConnectionBetweenLightClientsIdx) + if !exist || val == nil { + return false + } + v, ok := val.(bool) + if !ok { + return false + } + return v +} + func (whisper *Whisper) notifyPeersAboutPowRequirementChange(pow float64) { arr := whisper.getPeers() for _, p := range arr {