github.com/gobitfly/go-ethereum@v1.8.12/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/ethereum/go-ethereum/p2p" 28 "github.com/ethereum/go-ethereum/p2p/protocols" 29 "github.com/ethereum/go-ethereum/rlp" 30 "github.com/ethereum/go-ethereum/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 } 176 vrw = rw.(*PssReadWriter) 177 } 178 179 pmsg, err := ToP2pMsg(msg) 180 if err != nil { 181 return fmt.Errorf("could not decode pssmsg") 182 } 183 if asymmetric { 184 vrw = p.pubKeyRWPool[keyid].(*PssReadWriter) 185 } else { 186 vrw = p.symKeyRWPool[keyid].(*PssReadWriter) 187 } 188 vrw.injectMsg(pmsg) 189 return nil 190 } 191 192 // check if (peer) symmetric key is currently registered with this topic 193 func (p *Protocol) isActiveSymKey(key string, topic Topic) bool { 194 return p.symKeyRWPool[key] != nil 195 } 196 197 // check if (peer) asymmetric key is currently registered with this topic 198 func (p *Protocol) isActiveAsymKey(key string, topic Topic) bool { 199 return p.pubKeyRWPool[key] != nil 200 } 201 202 // Creates a serialized (non-buffered) version of a p2p.Msg, used in the specialized internal p2p.MsgReadwriter implementations 203 func ToP2pMsg(msg []byte) (p2p.Msg, error) { 204 payload := &ProtocolMsg{} 205 if err := rlp.DecodeBytes(msg, payload); err != nil { 206 return p2p.Msg{}, fmt.Errorf("pss protocol handler unable to decode payload as p2p message: %v", err) 207 } 208 209 return p2p.Msg{ 210 Code: payload.Code, 211 Size: uint32(len(payload.Payload)), 212 ReceivedAt: time.Now(), 213 Payload: bytes.NewBuffer(payload.Payload), 214 }, nil 215 } 216 217 // Runs an emulated pss Protocol on the specified peer, 218 // linked to a specific topic 219 // `key` and `asymmetric` specifies what encryption key 220 // to link the peer to. 221 // The key must exist in the pss store prior to adding the peer. 222 func (p *Protocol) AddPeer(peer *p2p.Peer, topic Topic, asymmetric bool, key string) (p2p.MsgReadWriter, error) { 223 rw := &PssReadWriter{ 224 Pss: p.Pss, 225 rw: make(chan p2p.Msg), 226 spec: p.spec, 227 topic: p.topic, 228 key: key, 229 } 230 if asymmetric { 231 rw.sendFunc = p.Pss.SendAsym 232 } else { 233 rw.sendFunc = p.Pss.SendSym 234 } 235 if asymmetric { 236 p.Pss.pubKeyPoolMu.Lock() 237 if _, ok := p.Pss.pubKeyPool[key]; !ok { 238 return nil, fmt.Errorf("asym key does not exist: %s", key) 239 } 240 p.Pss.pubKeyPoolMu.Unlock() 241 p.RWPoolMu.Lock() 242 p.pubKeyRWPool[key] = rw 243 p.RWPoolMu.Unlock() 244 } else { 245 p.Pss.symKeyPoolMu.Lock() 246 if _, ok := p.Pss.symKeyPool[key]; !ok { 247 return nil, fmt.Errorf("symkey does not exist: %s", key) 248 } 249 p.Pss.symKeyPoolMu.Unlock() 250 p.RWPoolMu.Lock() 251 p.symKeyRWPool[key] = rw 252 p.RWPoolMu.Unlock() 253 } 254 go func() { 255 err := p.proto.Run(peer, rw) 256 log.Warn(fmt.Sprintf("pss vprotocol quit on %v topic %v: %v", peer, topic, err)) 257 }() 258 return rw, nil 259 } 260 261 func (p *Protocol) RemovePeer(asymmetric bool, key string) { 262 log.Debug("closing pss peer", "asym", asymmetric, "key", key) 263 p.RWPoolMu.Lock() 264 defer p.RWPoolMu.Unlock() 265 if asymmetric { 266 rw := p.pubKeyRWPool[key].(*PssReadWriter) 267 rw.closed = true 268 delete(p.pubKeyRWPool, key) 269 } else { 270 rw := p.symKeyRWPool[key].(*PssReadWriter) 271 rw.closed = true 272 delete(p.symKeyRWPool, key) 273 } 274 } 275 276 // Uniform translation of protocol specifiers to topic 277 func ProtocolTopic(spec *protocols.Spec) Topic { 278 return BytesToTopic([]byte(fmt.Sprintf("%s:%d", spec.Name, spec.Version))) 279 }