github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/pss/protocol.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 //</624342678011645952> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 // 29 30 package pss 31 32 import ( 33 "bytes" 34 "fmt" 35 "sync" 36 "time" 37 38 "github.com/ethereum/go-ethereum/p2p" 39 "github.com/ethereum/go-ethereum/p2p/protocols" 40 "github.com/ethereum/go-ethereum/rlp" 41 "github.com/ethereum/go-ethereum/swarm/log" 42 ) 43 44 const ( 45 IsActiveProtocol = true 46 ) 47 48 // 49 type ProtocolMsg struct { 50 Code uint64 51 Size uint32 52 Payload []byte 53 ReceivedAt time.Time 54 } 55 56 // 57 func NewProtocolMsg(code uint64, msg interface{}) ([]byte, error) { 58 59 rlpdata, err := rlp.EncodeToBytes(msg) 60 if err != nil { 61 return nil, err 62 } 63 64 // 65 smsg := &ProtocolMsg{ 66 Code: code, 67 Size: uint32(len(rlpdata)), 68 Payload: rlpdata, 69 } 70 71 return rlp.EncodeToBytes(smsg) 72 } 73 74 // 75 // 76 // 77 type ProtocolParams struct { 78 Asymmetric bool 79 Symmetric bool 80 } 81 82 // 83 // 84 // 85 type PssReadWriter struct { 86 *Pss 87 LastActive time.Time 88 rw chan p2p.Msg 89 spec *protocols.Spec 90 topic *Topic 91 sendFunc func(string, Topic, []byte) error 92 key string 93 closed bool 94 } 95 96 // 97 func (prw *PssReadWriter) ReadMsg() (p2p.Msg, error) { 98 msg := <-prw.rw 99 log.Trace(fmt.Sprintf("pssrw readmsg: %v", msg)) 100 return msg, nil 101 } 102 103 // 104 func (prw *PssReadWriter) WriteMsg(msg p2p.Msg) error { 105 log.Trace("pssrw writemsg", "msg", msg) 106 if prw.closed { 107 return fmt.Errorf("connection closed") 108 } 109 rlpdata := make([]byte, msg.Size) 110 msg.Payload.Read(rlpdata) 111 pmsg, err := rlp.EncodeToBytes(ProtocolMsg{ 112 Code: msg.Code, 113 Size: msg.Size, 114 Payload: rlpdata, 115 }) 116 if err != nil { 117 return err 118 } 119 return prw.sendFunc(prw.key, *prw.topic, pmsg) 120 } 121 122 // 123 func (prw *PssReadWriter) injectMsg(msg p2p.Msg) error { 124 log.Trace(fmt.Sprintf("pssrw injectmsg: %v", msg)) 125 prw.rw <- msg 126 return nil 127 } 128 129 // 130 type Protocol struct { 131 *Pss 132 proto *p2p.Protocol 133 topic *Topic 134 spec *protocols.Spec 135 pubKeyRWPool map[string]p2p.MsgReadWriter 136 symKeyRWPool map[string]p2p.MsgReadWriter 137 Asymmetric bool 138 Symmetric bool 139 RWPoolMu sync.Mutex 140 } 141 142 // 143 // 144 // 145 // 146 // 147 // 148 func RegisterProtocol(ps *Pss, topic *Topic, spec *protocols.Spec, targetprotocol *p2p.Protocol, options *ProtocolParams) (*Protocol, error) { 149 if !options.Asymmetric && !options.Symmetric { 150 return nil, fmt.Errorf("specify at least one of asymmetric or symmetric messaging mode") 151 } 152 pp := &Protocol{ 153 Pss: ps, 154 proto: targetprotocol, 155 topic: topic, 156 spec: spec, 157 pubKeyRWPool: make(map[string]p2p.MsgReadWriter), 158 symKeyRWPool: make(map[string]p2p.MsgReadWriter), 159 Asymmetric: options.Asymmetric, 160 Symmetric: options.Symmetric, 161 } 162 return pp, nil 163 } 164 165 // 166 // 167 // 168 // 169 // 170 // 171 // 172 // 173 // 174 // 175 // 176 func (p *Protocol) Handle(msg []byte, peer *p2p.Peer, asymmetric bool, keyid string) error { 177 var vrw *PssReadWriter 178 if p.Asymmetric != asymmetric && p.Symmetric == !asymmetric { 179 return fmt.Errorf("invalid protocol encryption") 180 } else if (!p.isActiveSymKey(keyid, *p.topic) && !asymmetric) || 181 (!p.isActiveAsymKey(keyid, *p.topic) && asymmetric) { 182 183 rw, err := p.AddPeer(peer, *p.topic, asymmetric, keyid) 184 if err != nil { 185 return err 186 } else if rw == nil { 187 return fmt.Errorf("handle called on nil MsgReadWriter for new key " + keyid) 188 } 189 vrw = rw.(*PssReadWriter) 190 } 191 192 pmsg, err := ToP2pMsg(msg) 193 if err != nil { 194 return fmt.Errorf("could not decode pssmsg") 195 } 196 if asymmetric { 197 if p.pubKeyRWPool[keyid] == nil { 198 return fmt.Errorf("handle called on nil MsgReadWriter for key " + keyid) 199 } 200 vrw = p.pubKeyRWPool[keyid].(*PssReadWriter) 201 } else { 202 if p.symKeyRWPool[keyid] == nil { 203 return fmt.Errorf("handle called on nil MsgReadWriter for key " + keyid) 204 } 205 vrw = p.symKeyRWPool[keyid].(*PssReadWriter) 206 } 207 vrw.injectMsg(pmsg) 208 return nil 209 } 210 211 // 212 func (p *Protocol) isActiveSymKey(key string, topic Topic) bool { 213 return p.symKeyRWPool[key] != nil 214 } 215 216 // 217 func (p *Protocol) isActiveAsymKey(key string, topic Topic) bool { 218 return p.pubKeyRWPool[key] != nil 219 } 220 221 // 222 func ToP2pMsg(msg []byte) (p2p.Msg, error) { 223 payload := &ProtocolMsg{} 224 if err := rlp.DecodeBytes(msg, payload); err != nil { 225 return p2p.Msg{}, fmt.Errorf("pss protocol handler unable to decode payload as p2p message: %v", err) 226 } 227 228 return p2p.Msg{ 229 Code: payload.Code, 230 Size: uint32(len(payload.Payload)), 231 ReceivedAt: time.Now(), 232 Payload: bytes.NewBuffer(payload.Payload), 233 }, nil 234 } 235 236 // 237 // 238 // 239 // 240 // 241 func (p *Protocol) AddPeer(peer *p2p.Peer, topic Topic, asymmetric bool, key string) (p2p.MsgReadWriter, error) { 242 rw := &PssReadWriter{ 243 Pss: p.Pss, 244 rw: make(chan p2p.Msg), 245 spec: p.spec, 246 topic: p.topic, 247 key: key, 248 } 249 if asymmetric { 250 rw.sendFunc = p.Pss.SendAsym 251 } else { 252 rw.sendFunc = p.Pss.SendSym 253 } 254 if asymmetric { 255 p.Pss.pubKeyPoolMu.Lock() 256 if _, ok := p.Pss.pubKeyPool[key]; !ok { 257 return nil, fmt.Errorf("asym key does not exist: %s", key) 258 } 259 p.Pss.pubKeyPoolMu.Unlock() 260 p.RWPoolMu.Lock() 261 p.pubKeyRWPool[key] = rw 262 p.RWPoolMu.Unlock() 263 } else { 264 p.Pss.symKeyPoolMu.Lock() 265 if _, ok := p.Pss.symKeyPool[key]; !ok { 266 return nil, fmt.Errorf("symkey does not exist: %s", key) 267 } 268 p.Pss.symKeyPoolMu.Unlock() 269 p.RWPoolMu.Lock() 270 p.symKeyRWPool[key] = rw 271 p.RWPoolMu.Unlock() 272 } 273 go func() { 274 err := p.proto.Run(peer, rw) 275 log.Warn(fmt.Sprintf("pss vprotocol quit on %v topic %v: %v", peer, topic, err)) 276 }() 277 return rw, nil 278 } 279 280 func (p *Protocol) RemovePeer(asymmetric bool, key string) { 281 log.Debug("closing pss peer", "asym", asymmetric, "key", key) 282 p.RWPoolMu.Lock() 283 defer p.RWPoolMu.Unlock() 284 if asymmetric { 285 rw := p.pubKeyRWPool[key].(*PssReadWriter) 286 rw.closed = true 287 delete(p.pubKeyRWPool, key) 288 } else { 289 rw := p.symKeyRWPool[key].(*PssReadWriter) 290 rw.closed = true 291 delete(p.symKeyRWPool, key) 292 } 293 } 294 295 // 296 func ProtocolTopic(spec *protocols.Spec) Topic { 297 return BytesToTopic([]byte(fmt.Sprintf("%s:%d", spec.Name, spec.Version))) 298 } 299