whisper: add light mode check to handshake (#16725)
This commit is contained in:
parent
cf33d8b83c
commit
8711e2b636
|
@ -168,6 +168,9 @@ func makeFullNode(ctx *cli.Context) *node.Node {
|
||||||
if ctx.GlobalIsSet(utils.WhisperMinPOWFlag.Name) {
|
if ctx.GlobalIsSet(utils.WhisperMinPOWFlag.Name) {
|
||||||
cfg.Shh.MinimumAcceptedPOW = ctx.Float64(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)
|
utils.RegisterShhService(stack, &cfg.Shh)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,6 +151,7 @@ var (
|
||||||
utils.WhisperEnabledFlag,
|
utils.WhisperEnabledFlag,
|
||||||
utils.WhisperMaxMessageSizeFlag,
|
utils.WhisperMaxMessageSizeFlag,
|
||||||
utils.WhisperMinPOWFlag,
|
utils.WhisperMinPOWFlag,
|
||||||
|
utils.WhisperRestrictConnectionBetweenLightClientsFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
metricsFlags = []cli.Flag{
|
metricsFlags = []cli.Flag{
|
||||||
|
|
|
@ -567,6 +567,10 @@ var (
|
||||||
Usage: "Minimum POW accepted",
|
Usage: "Minimum POW accepted",
|
||||||
Value: whisper.DefaultMinimumPoW,
|
Value: whisper.DefaultMinimumPoW,
|
||||||
}
|
}
|
||||||
|
WhisperRestrictConnectionBetweenLightClientsFlag = cli.BoolFlag{
|
||||||
|
Name: "shh.restrict-light",
|
||||||
|
Usage: "Restrict connection between two whisper light clients",
|
||||||
|
}
|
||||||
|
|
||||||
// Metrics flags
|
// Metrics flags
|
||||||
MetricsEnabledFlag = cli.BoolFlag{
|
MetricsEnabledFlag = cli.BoolFlag{
|
||||||
|
@ -1099,6 +1103,9 @@ func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) {
|
||||||
if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) {
|
if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) {
|
||||||
cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(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.
|
// SetEthConfig applies eth-related command line flags to the config.
|
||||||
|
|
|
@ -195,14 +195,14 @@ func (api *PublicWhisperAPI) DeleteSymKey(ctx context.Context, id string) bool {
|
||||||
// MakeLightClient turns the node into light client, which does not forward
|
// MakeLightClient turns the node into light client, which does not forward
|
||||||
// any incoming messages, and sends only messages originated in this node.
|
// any incoming messages, and sends only messages originated in this node.
|
||||||
func (api *PublicWhisperAPI) MakeLightClient(ctx context.Context) bool {
|
func (api *PublicWhisperAPI) MakeLightClient(ctx context.Context) bool {
|
||||||
api.w.lightClient = true
|
api.w.SetLightClientMode(true)
|
||||||
return api.w.lightClient
|
return api.w.LightClientMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CancelLightClient cancels light client mode.
|
// CancelLightClient cancels light client mode.
|
||||||
func (api *PublicWhisperAPI) CancelLightClient(ctx context.Context) bool {
|
func (api *PublicWhisperAPI) CancelLightClient(ctx context.Context) bool {
|
||||||
api.w.lightClient = false
|
api.w.SetLightClientMode(false)
|
||||||
return !api.w.lightClient
|
return !api.w.LightClientMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:generate gencodec -type NewMessage -field-override newMessageOverride -out gen_newmessage_json.go
|
//go:generate gencodec -type NewMessage -field-override newMessageOverride -out gen_newmessage_json.go
|
||||||
|
|
|
@ -20,10 +20,12 @@ package whisperv6
|
||||||
type Config struct {
|
type Config struct {
|
||||||
MaxMessageSize uint32 `toml:",omitempty"`
|
MaxMessageSize uint32 `toml:",omitempty"`
|
||||||
MinimumAcceptedPOW float64 `toml:",omitempty"`
|
MinimumAcceptedPOW float64 `toml:",omitempty"`
|
||||||
|
RestrictConnectionBetweenLightClients bool `toml:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultConfig represents (shocker!) the default configuration.
|
// DefaultConfig represents (shocker!) the default configuration.
|
||||||
var DefaultConfig = Config{
|
var DefaultConfig = Config{
|
||||||
MaxMessageSize: DefaultMaxMessageSize,
|
MaxMessageSize: DefaultMaxMessageSize,
|
||||||
MinimumAcceptedPOW: DefaultMinimumPoW,
|
MinimumAcceptedPOW: DefaultMinimumPoW,
|
||||||
|
RestrictConnectionBetweenLightClients: true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,11 +79,14 @@ func (peer *Peer) stop() {
|
||||||
func (peer *Peer) handshake() error {
|
func (peer *Peer) handshake() error {
|
||||||
// Send the handshake status message asynchronously
|
// Send the handshake status message asynchronously
|
||||||
errc := make(chan error, 1)
|
errc := make(chan error, 1)
|
||||||
|
isLightNode := peer.host.LightClientMode()
|
||||||
|
isRestrictedLightNodeConnection := peer.host.LightClientModeConnectionRestricted()
|
||||||
go func() {
|
go func() {
|
||||||
pow := peer.host.MinPow()
|
pow := peer.host.MinPow()
|
||||||
powConverted := math.Float64bits(pow)
|
powConverted := math.Float64bits(pow)
|
||||||
bloom := peer.host.BloomFilter()
|
bloom := peer.host.BloomFilter()
|
||||||
errc <- p2p.SendItems(peer.ws, statusCode, ProtocolVersion, powConverted, bloom)
|
|
||||||
|
errc <- p2p.SendItems(peer.ws, statusCode, ProtocolVersion, powConverted, bloom, isLightNode)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Fetch the remote status packet and verify protocol match
|
// Fetch the remote status packet and verify protocol match
|
||||||
|
@ -127,6 +130,11 @@ func (peer *Peer) handshake() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isRemotePeerLightNode, err := s.Bool()
|
||||||
|
if isRemotePeerLightNode && isLightNode && isRestrictedLightNodeConnection {
|
||||||
|
return fmt.Errorf("peer [%x] is useless: two light client communication restricted", peer.ID())
|
||||||
|
}
|
||||||
|
|
||||||
if err := <-errc; err != nil {
|
if err := <-errc; err != nil {
|
||||||
return fmt.Errorf("peer [%x] failed to send status packet: %v", peer.ID(), err)
|
return fmt.Errorf("peer [%x] failed to send status packet: %v", peer.ID(), err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
var keys = []string{
|
var keys = []string{
|
||||||
|
@ -507,3 +508,63 @@ func waitForServersToStart(t *testing.T) {
|
||||||
}
|
}
|
||||||
t.Fatalf("Failed to start all the servers, running: %d", started)
|
t.Fatalf("Failed to start all the servers, running: %d", started)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//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()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//two light nodes handshake. restriction disabled
|
||||||
|
func TestTwoLightPeerHandshakeRestrictionOff(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 TestTwoLightPeerHandshakeError(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()
|
||||||
|
if err == nil {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type rwStub struct {
|
||||||
|
payload []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stub *rwStub) ReadMsg() (p2p.Msg, error) {
|
||||||
|
size, r, err := rlp.EncodeToReader(stub.payload)
|
||||||
|
if err != nil {
|
||||||
|
return p2p.Msg{}, err
|
||||||
|
}
|
||||||
|
return p2p.Msg{Code: statusCode, Size: uint32(size), Payload: r}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stub *rwStub) WriteMsg(m p2p.Msg) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -55,6 +55,8 @@ const (
|
||||||
minPowToleranceIdx // Minimal PoW tolerated by the whisper node for a limited time
|
minPowToleranceIdx // Minimal PoW tolerated by the whisper node for a limited time
|
||||||
bloomFilterIdx // Bloom filter for topics of interest for this node
|
bloomFilterIdx // Bloom filter for topics of interest for this node
|
||||||
bloomFilterToleranceIdx // Bloom filter tolerated by the whisper node for a limited time
|
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
|
// Whisper represents a dark communication interface through the Ethereum
|
||||||
|
@ -82,8 +84,6 @@ type Whisper struct {
|
||||||
|
|
||||||
syncAllowance int // maximum time in seconds allowed to process the whisper-related messages
|
syncAllowance int // maximum time in seconds allowed to process the whisper-related messages
|
||||||
|
|
||||||
lightClient bool // indicates is this node is pure light client (does not forward any messages)
|
|
||||||
|
|
||||||
statsMu sync.Mutex // guard stats
|
statsMu sync.Mutex // guard stats
|
||||||
stats Statistics // Statistics of whisper node
|
stats Statistics // Statistics of whisper node
|
||||||
|
|
||||||
|
@ -113,6 +113,7 @@ func New(cfg *Config) *Whisper {
|
||||||
whisper.settings.Store(minPowIdx, cfg.MinimumAcceptedPOW)
|
whisper.settings.Store(minPowIdx, cfg.MinimumAcceptedPOW)
|
||||||
whisper.settings.Store(maxMsgSizeIdx, cfg.MaxMessageSize)
|
whisper.settings.Store(maxMsgSizeIdx, cfg.MaxMessageSize)
|
||||||
whisper.settings.Store(overflowIdx, false)
|
whisper.settings.Store(overflowIdx, false)
|
||||||
|
whisper.settings.Store(restrictConnectionBetweenLightClientsIdx, cfg.RestrictConnectionBetweenLightClients)
|
||||||
|
|
||||||
// p2p whisper sub protocol handler
|
// p2p whisper sub protocol handler
|
||||||
whisper.protocol = p2p.Protocol{
|
whisper.protocol = p2p.Protocol{
|
||||||
|
@ -276,6 +277,31 @@ func (whisper *Whisper) SetMinimumPowTest(val float64) {
|
||||||
whisper.settings.Store(minPowToleranceIdx, val)
|
whisper.settings.Store(minPowToleranceIdx, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//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 light client (does not forward any messages)
|
||||||
|
func (whisper *Whisper) LightClientMode() bool {
|
||||||
|
val, exist := whisper.settings.Load(lightClientModeIdx)
|
||||||
|
if !exist || val == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
v, ok := val.(bool)
|
||||||
|
return v && ok
|
||||||
|
}
|
||||||
|
|
||||||
|
//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)
|
||||||
|
return v && ok
|
||||||
|
}
|
||||||
|
|
||||||
func (whisper *Whisper) notifyPeersAboutPowRequirementChange(pow float64) {
|
func (whisper *Whisper) notifyPeersAboutPowRequirementChange(pow float64) {
|
||||||
arr := whisper.getPeers()
|
arr := whisper.getPeers()
|
||||||
for _, p := range arr {
|
for _, p := range arr {
|
||||||
|
@ -672,7 +698,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
|
||||||
|
|
||||||
trouble := false
|
trouble := false
|
||||||
for _, env := range envelopes {
|
for _, env := range envelopes {
|
||||||
cached, err := whisper.add(env, whisper.lightClient)
|
cached, err := whisper.add(env, whisper.LightClientMode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
trouble = true
|
trouble = true
|
||||||
log.Error("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err)
|
log.Error("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err)
|
||||||
|
|
Loading…
Reference in New Issue