code: func (b *Bzz) RunProtocol(spec *protocols.Spec, run func(*BzzPeer) error) func(*p2p.Peer, p2p.MsgReadWriter) error {
  	return func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
  		// wait for the bzz protocol to perform the handshake
  		handshake, _ := b.GetOrCreateHandshake(p.ID())
  		defer b.removeHandshake(p.ID())
  		select {
  		case <-handshake.done:
  		case <-time.After(bzzHandshakeTimeout):
  			return fmt.Errorf("%08x: %s protocol timeout waiting for handshake on %08x", b.BaseAddr()[:4], spec.Name, p.ID().Bytes()[:4])
  		}
  		if handshake.err != nil {
  			return fmt.Errorf("%08x: %s protocol closed: %v", b.BaseAddr()[:4], spec.Name, handshake.err)
  		}
  		// the handshake has succeeded so construct the BzzPeer and run the protocol
  		peer := &BzzPeer{
  			Peer:       protocols.NewPeer(p, rw, spec),
  			BzzAddr:    handshake.peerAddr,
  			lastActive: time.Now(),
  			LightNode:  handshake.LightNode,
  		}
  
  		log.Debug("peer created", "addr", handshake.peerAddr.String())
  
  		return run(peer)
  	}
  }
docs: // RunProtocol is a wrapper for swarm subprotocols
  // returns a p2p protocol run function that can be assigned to p2p.Protocol#Run field
  // arguments:
  // * p2p protocol spec
  // * run function taking BzzPeer as argument
  //   this run function is meant to block for the duration of the protocol session
  //   on return the session is terminated and the peer is disconnected
  // the protocol waits for the bzz handshake is negotiated
  // the overlay address on the BzzPeer is set from the remote handshake