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