You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
6.2 KiB

  1. // Copyright 2017-2018 DERO Project. All rights reserved.
  2. // Use of this source code in any form is governed by RESEARCH license.
  3. // license can be found in the LICENSE file.
  4. // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
  5. //
  6. //
  7. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
  8. // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  10. // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  11. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  12. // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  13. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  14. // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  15. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. package p2p
  17. import "fmt"
  18. import "net"
  19. import "time"
  20. import "github.com/romana/rlog"
  21. import log "github.com/sirupsen/logrus"
  22. import "github.com/arnaucode/derosuite/globals"
  23. // the connection starts with P2P handshake
  24. // send the hand shake
  25. func Send_Handshake(connection *Connection) {
  26. // first request support flags
  27. if connection.Exit {
  28. return
  29. }
  30. Send_SupportFlags_Command(connection)
  31. connection.Lock()
  32. // lets do handshake
  33. var d Node_Data
  34. var c CORE_DATA
  35. var data_header Levin_Data_Header
  36. var levin_header Levin_Header
  37. d.Network_UUID = globals.Config.Network_ID
  38. d.Peer_ID = (uint64)(time.Now().Unix())
  39. c.Current_Height = chain.Get_Height()
  40. c.Cumulative_Difficulty = chain.Get_Difficulty()
  41. c.Top_Version = 6
  42. // top block id from the genesis or other block
  43. c.Top_ID = chain.Get_Top_ID()
  44. ds, _ := d.Serialize()
  45. cs, _ := c.Serialize()
  46. data_header.Data = ds
  47. data_header.Data = append(data_header.Data, cs...)
  48. levin_data, _ := data_header.Serialize()
  49. levin_header.CB = uint64(len(levin_data))
  50. levin_header.Command = P2P_COMMAND_HANDSHAKE
  51. levin_header.ReturnData = true
  52. levin_header.Flags = LEVIN_PACKET_REQUEST
  53. header_bytes, _ := levin_header.Serialize()
  54. connection.Conn.Write(header_bytes)
  55. connection.Conn.Write(levin_data)
  56. connection.Command_queue.PushBack(uint32(P2P_COMMAND_HANDSHAKE))
  57. connection.Unlock()
  58. }
  59. // handle P2P_COMMAND_HANDSHAKE,
  60. // we must send a response
  61. // our response is a boost compatible response which is parseable by old cryptonote daemons
  62. func Handle_P2P_Handshake_Command(connection *Connection,
  63. i_command_header *Levin_Header, buf []byte) {
  64. connection.logger.Infof("Handshake request arrived, we must parse it")
  65. // extract peers from our list, and insert them into the response
  66. // max 250 peers can be send ( since we are aiming compatibility with old daemons)
  67. var reply Node_Data_Response
  68. //panic("Handle_P2P_Handshake needs to fixed and tested")
  69. reply.NodeData.Network_UUID = globals.Config.Network_ID
  70. reply.NodeData.Peer_ID = (uint64)(OUR_PEER_ID)
  71. reply.NodeData.Local_time = uint64(time.Now().Unix())
  72. reply.CoreData.Current_Height = chain.Get_Height()
  73. reply.CoreData.Cumulative_Difficulty = chain.Get_Difficulty()
  74. reply.CoreData.Top_Version = 6
  75. // top block id from the genesis or other block
  76. // this data is from the block chain
  77. // this data must be the top block that we see till now
  78. reply.CoreData.Top_ID = chain.Get_Top_ID()
  79. for i := 0; i < 250; i++ {
  80. reply.PeerArray = append(reply.PeerArray,
  81. Peer_Info{IP: net.IPv4(byte(i), byte(i), byte(i), byte(i)), Port: 0, ID: 0, LastSeen: 0})
  82. }
  83. var o_command_header Levin_Header
  84. var o_data_header Levin_Data_Header
  85. o_data_header.Data, _ = reply.Serialize()
  86. data, _ := o_data_header.Serialize()
  87. // mark as containing 4 elements
  88. data[9] = 0x10
  89. o_command_header.CB = uint64(len(data))
  90. o_command_header.Command = P2P_COMMAND_HANDSHAKE
  91. o_command_header.ReturnData = false
  92. o_command_header.ReturnCode = 1 // send as good response
  93. o_command_header.Flags = LEVIN_PACKET_RESPONSE
  94. o_command_header_bytes, _ := o_command_header.Serialize()
  95. connection.Conn.Write(o_command_header_bytes)
  96. connection.Conn.Write(data)
  97. rlog.Tracef(4, "Sending handshake response\n")
  98. Handle_P2P_Handshake_Command_Response(connection, i_command_header, buf) // parse incoming response
  99. }
  100. /* handles response of our p2p command, parses data etc*/
  101. func Handle_P2P_Handshake_Command_Response(connection *Connection,
  102. i_command_header *Levin_Header, buf []byte) {
  103. var reply Node_Data_Response
  104. // deserialize data header
  105. var i_data_header Levin_Data_Header // incoming data header
  106. err := i_data_header.DeSerialize(buf)
  107. if err != nil {
  108. connection.logger.WithFields(log.Fields{
  109. "ip": connection.Addr.IP,
  110. }).Debugf("Disconnecting client, handshake could not be deserialized")
  111. return
  112. }
  113. if reply.DeSerialize(i_data_header.Data) != nil {
  114. logger.WithFields(log.Fields{
  115. "ip": connection.Addr.IP,
  116. }).Debugf("Disconnecting client, handshake could not be deserialized")
  117. return
  118. }
  119. if reply.NodeData.Network_UUID != globals.Config.Network_ID {
  120. logger.WithFields(log.Fields{
  121. "ip": connection.Addr.IP,
  122. "id": reply.NodeData.Network_UUID,
  123. }).Debugf("Disconnecting client, Wrong network ID")
  124. return
  125. }
  126. // we need to kick the peer if the height is something specific and peer id is less than ours
  127. // TODO right we are not doing it
  128. connection.Peer_ID = reply.NodeData.Peer_ID
  129. connection.Port = reply.NodeData.Local_Port
  130. connection.Last_Height = reply.CoreData.Current_Height
  131. connection.Top_Version = uint64(reply.CoreData.Top_Version)
  132. connection.Top_ID = reply.CoreData.Top_ID
  133. connection.Cumulative_Difficulty = reply.CoreData.Cumulative_Difficulty
  134. connection.State = ACTIVE
  135. connection.logger.WithFields(log.Fields{
  136. "PeerHeight": reply.CoreData.Current_Height,
  137. "Top Version": reply.CoreData.Top_Version,
  138. "Top_ID": fmt.Sprintf("%x", reply.CoreData.Top_ID),
  139. }).Debugf("Successful Handshake with Peer")
  140. // lets check whether we need to resync with this peer
  141. if chain.IsLagging(reply.CoreData.Cumulative_Difficulty, reply.CoreData.Current_Height, reply.CoreData.Top_ID) {
  142. logger.Debugf("We need to resync with the peer")
  143. // set mode to syncronising
  144. Send_BC_Notify_Chain_Command(connection)
  145. }
  146. }