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  }