github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/swarm/pss/protocol.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // +build !nopssprotocol
    18  
    19  package pss
    20  
    21  import (
    22  	"bytes"
    23  	"fmt"
    24  	"sync"
    25  	"time"
    26  
    27  	"github.com/FusionFoundation/efsn/p2p"
    28  	"github.com/FusionFoundation/efsn/p2p/protocols"
    29  	"github.com/FusionFoundation/efsn/rlp"
    30  	"github.com/FusionFoundation/efsn/swarm/log"
    31  )
    32  
    33  const (
    34  	IsActiveProtocol = true
    35  )
    36  
    37  // Convenience wrapper for devp2p protocol messages for transport over pss
    38  type ProtocolMsg struct {
    39  	Code       uint64
    40  	Size       uint32
    41  	Payload    []byte
    42  	ReceivedAt time.Time
    43  }
    44  
    45  // Creates a ProtocolMsg
    46  func NewProtocolMsg(code uint64, msg interface{}) ([]byte, error) {
    47  
    48  	rlpdata, err := rlp.EncodeToBytes(msg)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	// TODO verify that nested structs cannot be used in rlp
    54  	smsg := &ProtocolMsg{
    55  		Code:    code,
    56  		Size:    uint32(len(rlpdata)),
    57  		Payload: rlpdata,
    58  	}
    59  
    60  	return rlp.EncodeToBytes(smsg)
    61  }
    62  
    63  // Protocol options to be passed to a new Protocol instance
    64  //
    65  // The parameters specify which encryption schemes to allow
    66  type ProtocolParams struct {
    67  	Asymmetric bool
    68  	Symmetric  bool
    69  }
    70  
    71  // PssReadWriter bridges pss send/receive with devp2p protocol send/receive
    72  //
    73  // Implements p2p.MsgReadWriter
    74  type PssReadWriter struct {
    75  	*Pss
    76  	LastActive time.Time
    77  	rw         chan p2p.Msg
    78  	spec       *protocols.Spec
    79  	topic      *Topic
    80  	sendFunc   func(string, Topic, []byte) error
    81  	key        string
    82  	closed     bool
    83  }
    84  
    85  // Implements p2p.MsgReader
    86  func (prw *PssReadWriter) ReadMsg() (p2p.Msg, error) {
    87  	msg := <-prw.rw
    88  	log.Trace(fmt.Sprintf("pssrw readmsg: %v", msg))
    89  	return msg, nil
    90  }
    91  
    92  // Implements p2p.MsgWriter
    93  func (prw *PssReadWriter) WriteMsg(msg p2p.Msg) error {
    94  	log.Trace("pssrw writemsg", "msg", msg)
    95  	if prw.closed {
    96  		return fmt.Errorf("connection closed")
    97  	}
    98  	rlpdata := make([]byte, msg.Size)
    99  	msg.Payload.Read(rlpdata)
   100  	pmsg, err := rlp.EncodeToBytes(ProtocolMsg{
   101  		Code:    msg.Code,
   102  		Size:    msg.Size,
   103  		Payload: rlpdata,
   104  	})
   105  	if err != nil {
   106  		return err
   107  	}
   108  	return prw.sendFunc(prw.key, *prw.topic, pmsg)
   109  }
   110  
   111  // Injects a p2p.Msg into the MsgReadWriter, so that it appears on the associated p2p.MsgReader
   112  func (prw *PssReadWriter) injectMsg(msg p2p.Msg) error {
   113  	log.Trace(fmt.Sprintf("pssrw injectmsg: %v", msg))
   114  	prw.rw <- msg
   115  	return nil
   116  }
   117  
   118  // Convenience object for emulation devp2p over pss
   119  type Protocol struct {
   120  	*Pss
   121  	proto        *p2p.Protocol
   122  	topic        *Topic
   123  	spec         *protocols.Spec
   124  	pubKeyRWPool map[string]p2p.MsgReadWriter
   125  	symKeyRWPool map[string]p2p.MsgReadWriter
   126  	Asymmetric   bool
   127  	Symmetric    bool
   128  	RWPoolMu     sync.Mutex
   129  }
   130  
   131  // Activates devp2p emulation over a specific pss topic
   132  //
   133  // One or both encryption schemes must be specified. If
   134  // only one is specified, the protocol will not be valid
   135  // for the other, and will make the message handler
   136  // return errors
   137  func RegisterProtocol(ps *Pss, topic *Topic, spec *protocols.Spec, targetprotocol *p2p.Protocol, options *ProtocolParams) (*Protocol, error) {
   138  	if !options.Asymmetric && !options.Symmetric {
   139  		return nil, fmt.Errorf("specify at least one of asymmetric or symmetric messaging mode")
   140  	}
   141  	pp := &Protocol{
   142  		Pss:          ps,
   143  		proto:        targetprotocol,
   144  		topic:        topic,
   145  		spec:         spec,
   146  		pubKeyRWPool: make(map[string]p2p.MsgReadWriter),
   147  		symKeyRWPool: make(map[string]p2p.MsgReadWriter),
   148  		Asymmetric:   options.Asymmetric,
   149  		Symmetric:    options.Symmetric,
   150  	}
   151  	return pp, nil
   152  }
   153  
   154  // Generic handler for incoming messages over devp2p emulation
   155  //
   156  // To be passed to pss.Register()
   157  //
   158  // Will run the protocol on a new incoming peer, provided that
   159  // the encryption key of the message has a match in the internal
   160  // pss keypool
   161  //
   162  // Fails if protocol is not valid for the message encryption scheme,
   163  // if adding a new peer fails, or if the message is not a serialized
   164  // p2p.Msg (which it always will be if it is sent from this object).
   165  func (p *Protocol) Handle(msg []byte, peer *p2p.Peer, asymmetric bool, keyid string) error {
   166  	var vrw *PssReadWriter
   167  	if p.Asymmetric != asymmetric && p.Symmetric == !asymmetric {
   168  		return fmt.Errorf("invalid protocol encryption")
   169  	} else if (!p.isActiveSymKey(keyid, *p.topic) && !asymmetric) ||
   170  		(!p.isActiveAsymKey(keyid, *p.topic) && asymmetric) {
   171  
   172  		rw, err := p.AddPeer(peer, *p.topic, asymmetric, keyid)
   173  		if err != nil {
   174  			return err
   175  		} else if rw == nil {
   176  			return fmt.Errorf("handle called on nil MsgReadWriter for new key " + keyid)
   177  		}
   178  		vrw = rw.(*PssReadWriter)
   179  	}
   180  
   181  	pmsg, err := ToP2pMsg(msg)
   182  	if err != nil {
   183  		return fmt.Errorf("could not decode pssmsg")
   184  	}
   185  	if asymmetric {
   186  		if p.pubKeyRWPool[keyid] == nil {
   187  			return fmt.Errorf("handle called on nil MsgReadWriter for key " + keyid)
   188  		}
   189  		vrw = p.pubKeyRWPool[keyid].(*PssReadWriter)
   190  	} else {
   191  		if p.symKeyRWPool[keyid] == nil {
   192  			return fmt.Errorf("handle called on nil MsgReadWriter for key " + keyid)
   193  		}
   194  		vrw = p.symKeyRWPool[keyid].(*PssReadWriter)
   195  	}
   196  	vrw.injectMsg(pmsg)
   197  	return nil
   198  }
   199  
   200  // check if (peer) symmetric key is currently registered with this topic
   201  func (p *Protocol) isActiveSymKey(key string, topic Topic) bool {
   202  	return p.symKeyRWPool[key] != nil
   203  }
   204  
   205  // check if (peer) asymmetric key is currently registered with this topic
   206  func (p *Protocol) isActiveAsymKey(key string, topic Topic) bool {
   207  	return p.pubKeyRWPool[key] != nil
   208  }
   209  
   210  // Creates a serialized (non-buffered) version of a p2p.Msg, used in the specialized internal p2p.MsgReadwriter implementations
   211  func ToP2pMsg(msg []byte) (p2p.Msg, error) {
   212  	payload := &ProtocolMsg{}
   213  	if err := rlp.DecodeBytes(msg, payload); err != nil {
   214  		return p2p.Msg{}, fmt.Errorf("pss protocol handler unable to decode payload as p2p message: %v", err)
   215  	}
   216  
   217  	return p2p.Msg{
   218  		Code:       payload.Code,
   219  		Size:       uint32(len(payload.Payload)),
   220  		ReceivedAt: time.Now(),
   221  		Payload:    bytes.NewBuffer(payload.Payload),
   222  	}, nil
   223  }
   224  
   225  // Runs an emulated pss Protocol on the specified peer,
   226  // linked to a specific topic
   227  // `key` and `asymmetric` specifies what encryption key
   228  // to link the peer to.
   229  // The key must exist in the pss store prior to adding the peer.
   230  func (p *Protocol) AddPeer(peer *p2p.Peer, topic Topic, asymmetric bool, key string) (p2p.MsgReadWriter, error) {
   231  	rw := &PssReadWriter{
   232  		Pss:   p.Pss,
   233  		rw:    make(chan p2p.Msg),
   234  		spec:  p.spec,
   235  		topic: p.topic,
   236  		key:   key,
   237  	}
   238  	if asymmetric {
   239  		rw.sendFunc = p.Pss.SendAsym
   240  	} else {
   241  		rw.sendFunc = p.Pss.SendSym
   242  	}
   243  	if asymmetric {
   244  		p.Pss.pubKeyPoolMu.Lock()
   245  		if _, ok := p.Pss.pubKeyPool[key]; !ok {
   246  			return nil, fmt.Errorf("asym key does not exist: %s", key)
   247  		}
   248  		p.Pss.pubKeyPoolMu.Unlock()
   249  		p.RWPoolMu.Lock()
   250  		p.pubKeyRWPool[key] = rw
   251  		p.RWPoolMu.Unlock()
   252  	} else {
   253  		p.Pss.symKeyPoolMu.Lock()
   254  		if _, ok := p.Pss.symKeyPool[key]; !ok {
   255  			return nil, fmt.Errorf("symkey does not exist: %s", key)
   256  		}
   257  		p.Pss.symKeyPoolMu.Unlock()
   258  		p.RWPoolMu.Lock()
   259  		p.symKeyRWPool[key] = rw
   260  		p.RWPoolMu.Unlock()
   261  	}
   262  	go func() {
   263  		err := p.proto.Run(peer, rw)
   264  		log.Warn(fmt.Sprintf("pss vprotocol quit on %v topic %v: %v", peer, topic, err))
   265  	}()
   266  	return rw, nil
   267  }
   268  
   269  func (p *Protocol) RemovePeer(asymmetric bool, key string) {
   270  	log.Debug("closing pss peer", "asym", asymmetric, "key", key)
   271  	p.RWPoolMu.Lock()
   272  	defer p.RWPoolMu.Unlock()
   273  	if asymmetric {
   274  		rw := p.pubKeyRWPool[key].(*PssReadWriter)
   275  		rw.closed = true
   276  		delete(p.pubKeyRWPool, key)
   277  	} else {
   278  		rw := p.symKeyRWPool[key].(*PssReadWriter)
   279  		rw.closed = true
   280  		delete(p.symKeyRWPool, key)
   281  	}
   282  }
   283  
   284  // Uniform translation of protocol specifiers to topic
   285  func ProtocolTopic(spec *protocols.Spec) Topic {
   286  	return BytesToTopic([]byte(fmt.Sprintf("%s:%d", spec.Name, spec.Version)))
   287  }