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