github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/pss/client/client.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:48</date>
    10  //</624342677189562368>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  //
    29  
    30  package client
    31  
    32  import (
    33  	"context"
    34  	"errors"
    35  	"fmt"
    36  	"sync"
    37  	"time"
    38  
    39  	"github.com/ethereum/go-ethereum/common/hexutil"
    40  	"github.com/ethereum/go-ethereum/p2p"
    41  	"github.com/ethereum/go-ethereum/p2p/discover"
    42  	"github.com/ethereum/go-ethereum/p2p/protocols"
    43  	"github.com/ethereum/go-ethereum/rlp"
    44  	"github.com/ethereum/go-ethereum/rpc"
    45  	"github.com/ethereum/go-ethereum/swarm/log"
    46  	"github.com/ethereum/go-ethereum/swarm/pss"
    47  )
    48  
    49  const (
    50  	handshakeRetryTimeout = 1000
    51  	handshakeRetryCount   = 3
    52  )
    53  
    54  //
    55  //
    56  type Client struct {
    57  	BaseAddrHex string
    58  
    59  //
    60  	peerPool map[pss.Topic]map[string]*pssRPCRW
    61  	protos   map[pss.Topic]*p2p.Protocol
    62  
    63  //
    64  	rpc  *rpc.Client
    65  	subs []*rpc.ClientSubscription
    66  
    67  //
    68  	topicsC chan []byte
    69  	quitC   chan struct{}
    70  
    71  	poolMu sync.Mutex
    72  }
    73  
    74  //
    75  type pssRPCRW struct {
    76  	*Client
    77  	topic    string
    78  	msgC     chan []byte
    79  	addr     pss.PssAddress
    80  	pubKeyId string
    81  	lastSeen time.Time
    82  	closed   bool
    83  }
    84  
    85  func (c *Client) newpssRPCRW(pubkeyid string, addr pss.PssAddress, topicobj pss.Topic) (*pssRPCRW, error) {
    86  	topic := topicobj.String()
    87  	err := c.rpc.Call(nil, "pss_setPeerPublicKey", pubkeyid, topic, hexutil.Encode(addr[:]))
    88  	if err != nil {
    89  		return nil, fmt.Errorf("setpeer %s %s: %v", topic, pubkeyid, err)
    90  	}
    91  	return &pssRPCRW{
    92  		Client:   c,
    93  		topic:    topic,
    94  		msgC:     make(chan []byte),
    95  		addr:     addr,
    96  		pubKeyId: pubkeyid,
    97  	}, nil
    98  }
    99  
   100  func (rw *pssRPCRW) ReadMsg() (p2p.Msg, error) {
   101  	msg := <-rw.msgC
   102  	log.Trace("pssrpcrw read", "msg", msg)
   103  	pmsg, err := pss.ToP2pMsg(msg)
   104  	if err != nil {
   105  		return p2p.Msg{}, err
   106  	}
   107  
   108  	return pmsg, nil
   109  }
   110  
   111  //
   112  //
   113  //
   114  //
   115  //
   116  //
   117  //
   118  //
   119  func (rw *pssRPCRW) WriteMsg(msg p2p.Msg) error {
   120  	log.Trace("got writemsg pssclient", "msg", msg)
   121  	if rw.closed {
   122  		return fmt.Errorf("connection closed")
   123  	}
   124  	rlpdata := make([]byte, msg.Size)
   125  	msg.Payload.Read(rlpdata)
   126  	pmsg, err := rlp.EncodeToBytes(pss.ProtocolMsg{
   127  		Code:    msg.Code,
   128  		Size:    msg.Size,
   129  		Payload: rlpdata,
   130  	})
   131  	if err != nil {
   132  		return err
   133  	}
   134  
   135  //
   136  	var symkeyids []string
   137  	err = rw.Client.rpc.Call(&symkeyids, "pss_getHandshakeKeys", rw.pubKeyId, rw.topic, false, true)
   138  	if err != nil {
   139  		return err
   140  	}
   141  
   142  //
   143  	var symkeycap uint16
   144  	if len(symkeyids) > 0 {
   145  		err = rw.Client.rpc.Call(&symkeycap, "pss_getHandshakeKeyCapacity", symkeyids[0])
   146  		if err != nil {
   147  			return err
   148  		}
   149  	}
   150  
   151  	err = rw.Client.rpc.Call(nil, "pss_sendSym", symkeyids[0], rw.topic, hexutil.Encode(pmsg))
   152  	if err != nil {
   153  		return err
   154  	}
   155  
   156  //
   157  	if symkeycap == 1 {
   158  		var retries int
   159  		var sync bool
   160  //
   161  		if len(symkeyids) == 1 {
   162  			sync = true
   163  		}
   164  //
   165  		_, err := rw.handshake(retries, sync, false)
   166  		if err != nil {
   167  			log.Warn("failing", "err", err)
   168  			return err
   169  		}
   170  	}
   171  	return nil
   172  }
   173  
   174  //
   175  //
   176  func (rw *pssRPCRW) handshake(retries int, sync bool, flush bool) (string, error) {
   177  
   178  	var symkeyids []string
   179  	var i int
   180  //
   181  //
   182  	for i = 0; i < 1+retries; i++ {
   183  		log.Debug("handshake attempt pssrpcrw", "pubkeyid", rw.pubKeyId, "topic", rw.topic, "sync", sync)
   184  		err := rw.Client.rpc.Call(&symkeyids, "pss_handshake", rw.pubKeyId, rw.topic, sync, flush)
   185  		if err == nil {
   186  			var keyid string
   187  			if sync {
   188  				keyid = symkeyids[0]
   189  			}
   190  			return keyid, nil
   191  		}
   192  		if i-1+retries > 1 {
   193  			time.Sleep(time.Millisecond * handshakeRetryTimeout)
   194  		}
   195  	}
   196  
   197  	return "", fmt.Errorf("handshake failed after %d attempts", i)
   198  }
   199  
   200  //
   201  //
   202  //
   203  func NewClient(rpcurl string) (*Client, error) {
   204  	rpcclient, err := rpc.Dial(rpcurl)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  
   209  	client, err := NewClientWithRPC(rpcclient)
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  	return client, nil
   214  }
   215  
   216  //
   217  //
   218  //
   219  func NewClientWithRPC(rpcclient *rpc.Client) (*Client, error) {
   220  	client := newClient()
   221  	client.rpc = rpcclient
   222  	err := client.rpc.Call(&client.BaseAddrHex, "pss_baseAddr")
   223  	if err != nil {
   224  		return nil, fmt.Errorf("cannot get pss node baseaddress: %v", err)
   225  	}
   226  	return client, nil
   227  }
   228  
   229  func newClient() (client *Client) {
   230  	client = &Client{
   231  		quitC:    make(chan struct{}),
   232  		peerPool: make(map[pss.Topic]map[string]*pssRPCRW),
   233  		protos:   make(map[pss.Topic]*p2p.Protocol),
   234  	}
   235  	return
   236  }
   237  
   238  //
   239  //
   240  //
   241  //
   242  //
   243  //
   244  //
   245  func (c *Client) RunProtocol(ctx context.Context, proto *p2p.Protocol) error {
   246  	topicobj := pss.BytesToTopic([]byte(fmt.Sprintf("%s:%d", proto.Name, proto.Version)))
   247  	topichex := topicobj.String()
   248  	msgC := make(chan pss.APIMsg)
   249  	c.peerPool[topicobj] = make(map[string]*pssRPCRW)
   250  	sub, err := c.rpc.Subscribe(ctx, "pss", msgC, "receive", topichex)
   251  	if err != nil {
   252  		return fmt.Errorf("pss event subscription failed: %v", err)
   253  	}
   254  	c.subs = append(c.subs, sub)
   255  	err = c.rpc.Call(nil, "pss_addHandshake", topichex)
   256  	if err != nil {
   257  		return fmt.Errorf("pss handshake activation failed: %v", err)
   258  	}
   259  
   260  //
   261  	go func() {
   262  		for {
   263  			select {
   264  			case msg := <-msgC:
   265  //
   266  				if msg.Asymmetric {
   267  					continue
   268  				}
   269  //
   270  //
   271  				var pubkeyid string
   272  				err = c.rpc.Call(&pubkeyid, "pss_getHandshakePublicKey", msg.Key)
   273  				if err != nil || pubkeyid == "" {
   274  					log.Trace("proto err or no pubkey", "err", err, "symkeyid", msg.Key)
   275  					continue
   276  				}
   277  //
   278  //
   279  				if c.peerPool[topicobj][pubkeyid] == nil {
   280  					var addrhex string
   281  					err := c.rpc.Call(&addrhex, "pss_getAddress", topichex, false, msg.Key)
   282  					if err != nil {
   283  						log.Trace(err.Error())
   284  						continue
   285  					}
   286  					addrbytes, err := hexutil.Decode(addrhex)
   287  					if err != nil {
   288  						log.Trace(err.Error())
   289  						break
   290  					}
   291  					addr := pss.PssAddress(addrbytes)
   292  					rw, err := c.newpssRPCRW(pubkeyid, addr, topicobj)
   293  					if err != nil {
   294  						break
   295  					}
   296  					c.peerPool[topicobj][pubkeyid] = rw
   297  					nid, _ := discover.HexID("0x00")
   298  					p := p2p.NewPeer(nid, fmt.Sprintf("%v", addr), []p2p.Cap{})
   299  					go proto.Run(p, c.peerPool[topicobj][pubkeyid])
   300  				}
   301  				go func() {
   302  					c.peerPool[topicobj][pubkeyid].msgC <- msg.Msg
   303  				}()
   304  			case <-c.quitC:
   305  				return
   306  			}
   307  		}
   308  	}()
   309  
   310  	c.protos[topicobj] = proto
   311  	return nil
   312  }
   313  
   314  //
   315  func (c *Client) Close() error {
   316  	for _, s := range c.subs {
   317  		s.Unsubscribe()
   318  	}
   319  	return nil
   320  }
   321  
   322  //
   323  //
   324  //
   325  //
   326  //
   327  //
   328  //
   329  //
   330  //
   331  func (c *Client) AddPssPeer(pubkeyid string, addr []byte, spec *protocols.Spec) error {
   332  	topic := pss.ProtocolTopic(spec)
   333  	if c.peerPool[topic] == nil {
   334  		return errors.New("addpeer on unset topic")
   335  	}
   336  	if c.peerPool[topic][pubkeyid] == nil {
   337  		rw, err := c.newpssRPCRW(pubkeyid, addr, topic)
   338  		if err != nil {
   339  			return err
   340  		}
   341  		_, err = rw.handshake(handshakeRetryCount, true, true)
   342  		if err != nil {
   343  			return err
   344  		}
   345  		c.poolMu.Lock()
   346  		c.peerPool[topic][pubkeyid] = rw
   347  		c.poolMu.Unlock()
   348  		nid, _ := discover.HexID("0x00")
   349  		p := p2p.NewPeer(nid, fmt.Sprintf("%v", addr), []p2p.Cap{})
   350  		go c.protos[topic].Run(p, c.peerPool[topic][pubkeyid])
   351  	}
   352  	return nil
   353  }
   354  
   355  //
   356  //
   357  //
   358  func (c *Client) RemovePssPeer(pubkeyid string, spec *protocols.Spec) {
   359  	log.Debug("closing pss client peer", "pubkey", pubkeyid, "protoname", spec.Name, "protoversion", spec.Version)
   360  	c.poolMu.Lock()
   361  	defer c.poolMu.Unlock()
   362  	topic := pss.ProtocolTopic(spec)
   363  	c.peerPool[topic][pubkeyid].closed = true
   364  	delete(c.peerPool[topic], pubkeyid)
   365  }
   366