github.com/alanchchen/go-ethereum@v1.6.6-0.20170601190819-6171d01b1195/swarm/network/messages.go (about) 1 // Copyright 2016 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 package network 18 19 import ( 20 "fmt" 21 "net" 22 "time" 23 24 "github.com/ethereum/go-ethereum/contracts/chequebook" 25 "github.com/ethereum/go-ethereum/p2p/discover" 26 "github.com/ethereum/go-ethereum/swarm/network/kademlia" 27 "github.com/ethereum/go-ethereum/swarm/services/swap" 28 "github.com/ethereum/go-ethereum/swarm/storage" 29 ) 30 31 /* 32 BZZ protocol Message Types and Message Data Types 33 */ 34 35 // bzz protocol message codes 36 const ( 37 statusMsg = iota // 0x01 38 storeRequestMsg // 0x02 39 retrieveRequestMsg // 0x03 40 peersMsg // 0x04 41 syncRequestMsg // 0x05 42 deliveryRequestMsg // 0x06 43 unsyncedKeysMsg // 0x07 44 paymentMsg // 0x08 45 ) 46 47 /* 48 Handshake 49 50 * Version: 8 byte integer version of the protocol 51 * ID: arbitrary byte sequence client identifier human readable 52 * Addr: the address advertised by the node, format similar to DEVp2p wire protocol 53 * Swap: info for the swarm accounting protocol 54 * NetworkID: 8 byte integer network identifier 55 * Caps: swarm-specific capabilities, format identical to devp2p 56 * SyncState: syncronisation state (db iterator key and address space etc) persisted about the peer 57 58 */ 59 type statusMsgData struct { 60 Version uint64 61 ID string 62 Addr *peerAddr 63 Swap *swap.SwapProfile 64 NetworkId uint64 65 } 66 67 func (self *statusMsgData) String() string { 68 return fmt.Sprintf("Status: Version: %v, ID: %v, Addr: %v, Swap: %v, NetworkId: %v", self.Version, self.ID, self.Addr, self.Swap, self.NetworkId) 69 } 70 71 /* 72 store requests are forwarded to the peers in their kademlia proximity bin 73 if they are distant 74 if they are within our storage radius or have any incentive to store it 75 then attach your nodeID to the metadata 76 if the storage request is sufficiently close (within our proxLimit, i. e., the 77 last row of the routing table) 78 */ 79 type storeRequestMsgData struct { 80 Key storage.Key // hash of datasize | data 81 SData []byte // the actual chunk Data 82 // optional 83 Id uint64 // request ID. if delivery, the ID is retrieve request ID 84 requestTimeout *time.Time // expiry for forwarding - [not serialised][not currently used] 85 storageTimeout *time.Time // expiry of content - [not serialised][not currently used] 86 from *peer // [not serialised] protocol registers the requester 87 } 88 89 func (self storeRequestMsgData) String() string { 90 var from string 91 if self.from == nil { 92 from = "self" 93 } else { 94 from = self.from.Addr().String() 95 } 96 end := len(self.SData) 97 if len(self.SData) > 10 { 98 end = 10 99 } 100 return fmt.Sprintf("from: %v, Key: %v; ID: %v, requestTimeout: %v, storageTimeout: %v, SData %x", from, self.Key, self.Id, self.requestTimeout, self.storageTimeout, self.SData[:end]) 101 } 102 103 /* 104 Retrieve request 105 106 Timeout in milliseconds. Note that zero timeout retrieval requests do not request forwarding, but prompt for a peers message response. therefore they serve also 107 as messages to retrieve peers. 108 109 MaxSize specifies the maximum size that the peer will accept. This is useful in 110 particular if we allow storage and delivery of multichunk payload representing 111 the entire or partial subtree unfolding from the requested root key. 112 So when only interested in limited part of a stream (infinite trees) or only 113 testing chunk availability etc etc, we can indicate it by limiting the size here. 114 115 Request ID can be newly generated or kept from the request originator. 116 If request ID Is missing or zero, the request is handled as a lookup only 117 prompting a peers response but not launching a search. Lookup requests are meant 118 to be used to bootstrap kademlia tables. 119 120 In the special case that the key is the zero value as well, the remote peer's 121 address is assumed (the message is to be handled as a self lookup request). 122 The response is a PeersMsg with the peers in the kademlia proximity bin 123 corresponding to the address. 124 */ 125 126 type retrieveRequestMsgData struct { 127 Key storage.Key // target Key address of chunk to be retrieved 128 Id uint64 // request id, request is a lookup if missing or zero 129 MaxSize uint64 // maximum size of delivery accepted 130 MaxPeers uint64 // maximum number of peers returned 131 Timeout uint64 // the longest time we are expecting a response 132 timeout *time.Time // [not serialied] 133 from *peer // 134 } 135 136 func (self retrieveRequestMsgData) String() string { 137 var from string 138 if self.from == nil { 139 from = "ourselves" 140 } else { 141 from = self.from.Addr().String() 142 } 143 var target []byte 144 if len(self.Key) > 3 { 145 target = self.Key[:4] 146 } 147 return fmt.Sprintf("from: %v, Key: %x; ID: %v, MaxSize: %v, MaxPeers: %d", from, target, self.Id, self.MaxSize, self.MaxPeers) 148 } 149 150 // lookups are encoded by missing request ID 151 func (self retrieveRequestMsgData) isLookup() bool { 152 return self.Id == 0 153 } 154 155 // sets timeout fields 156 func (self retrieveRequestMsgData) setTimeout(t *time.Time) { 157 self.timeout = t 158 if t != nil { 159 self.Timeout = uint64(t.UnixNano()) 160 } else { 161 self.Timeout = 0 162 } 163 } 164 165 func (self retrieveRequestMsgData) getTimeout() (t *time.Time) { 166 if self.Timeout > 0 && self.timeout == nil { 167 timeout := time.Unix(int64(self.Timeout), 0) 168 t = &timeout 169 self.timeout = t 170 } 171 return 172 } 173 174 // peerAddr is sent in StatusMsg as part of the handshake 175 type peerAddr struct { 176 IP net.IP 177 Port uint16 178 ID []byte // the 64 byte NodeID (ECDSA Public Key) 179 Addr kademlia.Address 180 } 181 182 // peerAddr pretty prints as enode 183 func (self peerAddr) String() string { 184 var nodeid discover.NodeID 185 copy(nodeid[:], self.ID) 186 return discover.NewNode(nodeid, self.IP, 0, self.Port).String() 187 } 188 189 /* 190 peers Msg is one response to retrieval; it is always encouraged after a retrieval 191 request to respond with a list of peers in the same kademlia proximity bin. 192 The encoding of a peer is identical to that in the devp2p base protocol peers 193 messages: [IP, Port, NodeID] 194 note that a node's DPA address is not the NodeID but the hash of the NodeID. 195 196 Timeout serves to indicate whether the responder is forwarding the query within 197 the timeout or not. 198 199 NodeID serves as the owner of payment contracts and signer of proofs of transfer. 200 201 The Key is the target (if response to a retrieval request) or missing (zero value) 202 peers address (hash of NodeID) if retrieval request was a self lookup. 203 204 Peers message is requested by retrieval requests with a missing or zero value request ID 205 */ 206 type peersMsgData struct { 207 Peers []*peerAddr // 208 Timeout uint64 // 209 timeout *time.Time // indicate whether responder is expected to deliver content 210 Key storage.Key // present if a response to a retrieval request 211 Id uint64 // present if a response to a retrieval request 212 from *peer 213 } 214 215 // peers msg pretty printer 216 func (self peersMsgData) String() string { 217 var from string 218 if self.from == nil { 219 from = "ourselves" 220 } else { 221 from = self.from.Addr().String() 222 } 223 var target []byte 224 if len(self.Key) > 3 { 225 target = self.Key[:4] 226 } 227 return fmt.Sprintf("from: %v, Key: %x; ID: %v, Peers: %v", from, target, self.Id, self.Peers) 228 } 229 230 func (self peersMsgData) setTimeout(t *time.Time) { 231 self.timeout = t 232 if t != nil { 233 self.Timeout = uint64(t.UnixNano()) 234 } else { 235 self.Timeout = 0 236 } 237 } 238 239 func (self peersMsgData) getTimeout() (t *time.Time) { 240 if self.Timeout > 0 && self.timeout == nil { 241 timeout := time.Unix(int64(self.Timeout), 0) 242 t = &timeout 243 self.timeout = t 244 } 245 return 246 } 247 248 /* 249 syncRequest 250 251 is sent after the handshake to initiate syncing 252 the syncState of the remote node is persisted in kaddb and set on the 253 peer/protocol instance when the node is registered by hive as online{ 254 */ 255 256 type syncRequestMsgData struct { 257 SyncState *syncState `rlp:"nil"` 258 } 259 260 func (self *syncRequestMsgData) String() string { 261 return fmt.Sprintf("%v", self.SyncState) 262 } 263 264 /* 265 deliveryRequest 266 267 is sent once a batch of sync keys is filtered. The ones not found are 268 sent as a list of syncReuest (hash, priority) in the Deliver field. 269 When the source receives the sync request it continues to iterate 270 and fetch at most N items as yet unsynced. 271 At the same time responds with deliveries of the items. 272 */ 273 type deliveryRequestMsgData struct { 274 Deliver []*syncRequest 275 } 276 277 func (self *deliveryRequestMsgData) String() string { 278 return fmt.Sprintf("sync request for new chunks\ndelivery request for %v chunks", len(self.Deliver)) 279 } 280 281 /* 282 unsyncedKeys 283 284 is sent first after the handshake if SyncState iterator brings up hundreds, thousands? 285 and subsequently sent as a response to deliveryRequestMsgData. 286 287 Syncing is the iterative process of exchanging unsyncedKeys and deliveryRequestMsgs 288 both ways. 289 290 State contains the sync state sent by the source. When the source receives the 291 sync state it continues to iterate and fetch at most N items as yet unsynced. 292 At the same time responds with deliveries of the items. 293 */ 294 type unsyncedKeysMsgData struct { 295 Unsynced []*syncRequest 296 State *syncState 297 } 298 299 func (self *unsyncedKeysMsgData) String() string { 300 return fmt.Sprintf("sync: keys of %d new chunks (state %v) => synced: %v", len(self.Unsynced), self.State, self.State.Synced) 301 } 302 303 /* 304 payment 305 306 is sent when the swap balance is tilted in favour of the remote peer 307 and in absolute units exceeds the PayAt parameter in the remote peer's profile 308 */ 309 310 type paymentMsgData struct { 311 Units uint // units actually paid for (checked against amount by swap) 312 Promise *chequebook.Cheque // payment with cheque 313 } 314 315 func (self *paymentMsgData) String() string { 316 return fmt.Sprintf("payment for %d units: %v", self.Units, self.Promise) 317 }