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.

194 lines
5.2 KiB

  1. package p2p
  2. import "fmt"
  3. import "net"
  4. import "time"
  5. import "github.com/romana/rlog"
  6. import log "github.com/sirupsen/logrus"
  7. import "github.com/deroproject/derosuite/globals"
  8. // the connection starts with P2P handshake
  9. // send the hand shake
  10. func Send_Handshake(connection *Connection) {
  11. // first request support flags
  12. if connection.Exit {
  13. return
  14. }
  15. Send_SupportFlags_Command(connection)
  16. connection.Lock()
  17. // lets do handshake
  18. var d Node_Data
  19. var c CORE_DATA
  20. var data_header Levin_Data_Header
  21. var levin_header Levin_Header
  22. d.Network_UUID = globals.Config.Network_ID
  23. d.Peer_ID = (uint64)(time.Now().Unix())
  24. c.Current_Height = chain.Get_Height()
  25. c.Cumulative_Difficulty = chain.Get_Difficulty()
  26. c.Top_Version = 6
  27. // top block id from the genesis or other block
  28. c.Top_ID = chain.Get_Top_ID()
  29. ds, _ := d.Serialize()
  30. cs, _ := c.Serialize()
  31. data_header.Data = ds
  32. data_header.Data = append(data_header.Data, cs...)
  33. levin_data, _ := data_header.Serialize()
  34. levin_header.CB = uint64(len(levin_data))
  35. levin_header.Command = P2P_COMMAND_HANDSHAKE
  36. levin_header.ReturnData = true
  37. levin_header.Flags = LEVIN_PACKET_REQUEST
  38. header_bytes, _ := levin_header.Serialize()
  39. connection.Conn.Write(header_bytes)
  40. connection.Conn.Write(levin_data)
  41. connection.Command_queue.PushBack(uint32(P2P_COMMAND_HANDSHAKE))
  42. connection.Unlock()
  43. }
  44. // handle P2P_COMMAND_HANDSHAKE,
  45. // we must send a response
  46. // our response is a boost compatible response which is parseable by old cryptonote daemons
  47. func Handle_P2P_Handshake_Command(connection *Connection,
  48. i_command_header *Levin_Header, buf []byte) {
  49. connection.logger.Infof("Handshake request arrived, we must parse it")
  50. // extract peers from our list, and insert them into the response
  51. // max 250 peers can be send ( since we are aiming compatibility with old daemons)
  52. var reply Node_Data_Response
  53. //panic("Handle_P2P_Handshake needs to fixed and tested")
  54. reply.NodeData.Network_UUID = globals.Config.Network_ID
  55. reply.NodeData.Peer_ID = (uint64)(OUR_PEER_ID)
  56. reply.NodeData.Local_time = uint64(time.Now().Unix())
  57. reply.CoreData.Current_Height = chain.Get_Height()
  58. reply.CoreData.Cumulative_Difficulty = chain.Get_Difficulty()
  59. reply.CoreData.Top_Version = 6
  60. // top block id from the genesis or other block
  61. // this data is from the block chain
  62. // this data must be the top block that we see till now
  63. reply.CoreData.Top_ID = chain.Get_Top_ID()
  64. for i := 0; i < 250; i++ {
  65. reply.PeerArray = append(reply.PeerArray,
  66. Peer_Info{IP: net.IPv4(byte(i), byte(i), byte(i), byte(i)), Port: 0, ID: 0, LastSeen: 0})
  67. }
  68. var o_command_header Levin_Header
  69. var o_data_header Levin_Data_Header
  70. o_data_header.Data, _ = reply.Serialize()
  71. data, _ := o_data_header.Serialize()
  72. // mark as containing 4 elements
  73. data[9] = 0x10
  74. o_command_header.CB = uint64(len(data))
  75. o_command_header.Command = P2P_COMMAND_HANDSHAKE
  76. o_command_header.ReturnData = false
  77. o_command_header.ReturnCode = 1 // send as good response
  78. o_command_header.Flags = LEVIN_PACKET_RESPONSE
  79. o_command_header_bytes, _ := o_command_header.Serialize()
  80. connection.Conn.Write(o_command_header_bytes)
  81. connection.Conn.Write(data)
  82. rlog.Tracef(4, "Sending handshake response\n")
  83. Handle_P2P_Handshake_Command_Response(connection, i_command_header,buf) // parse incoming response
  84. }
  85. /* handles response of our p2p command, parses data etc*/
  86. func Handle_P2P_Handshake_Command_Response(connection *Connection,
  87. i_command_header *Levin_Header, buf []byte) {
  88. var reply Node_Data_Response
  89. // deserialize data header
  90. var i_data_header Levin_Data_Header // incoming data header
  91. err := i_data_header.DeSerialize(buf)
  92. if err != nil {
  93. connection.logger.WithFields(log.Fields{
  94. "ip": connection.Addr.IP,
  95. }).Debugf("Disconnecting client, handshake could not be deserialized")
  96. return
  97. }
  98. if reply.DeSerialize(i_data_header.Data) != nil {
  99. logger.WithFields(log.Fields{
  100. "ip": connection.Addr.IP,
  101. }).Debugf("Disconnecting client, handshake could not be deserialized")
  102. return
  103. }
  104. if reply.NodeData.Network_UUID != globals.Config.Network_ID {
  105. logger.WithFields(log.Fields{
  106. "ip": connection.Addr.IP,
  107. "id": reply.NodeData.Network_UUID,
  108. }).Debugf("Disconnecting client, Wrong network ID")
  109. return
  110. }
  111. // we need to kick the peer if the height is something specific and peer id is less than ours
  112. // TODO right we are not doing it
  113. connection.Peer_ID = reply.NodeData.Peer_ID
  114. connection.Port = reply.NodeData.Local_Port
  115. connection.Last_Height = reply.CoreData.Current_Height
  116. connection.Top_Version = uint64(reply.CoreData.Top_Version)
  117. connection.Top_ID = reply.CoreData.Top_ID
  118. connection.Cumulative_Difficulty = reply.CoreData.Cumulative_Difficulty
  119. connection.State = ACTIVE
  120. connection.logger.WithFields(log.Fields{
  121. "PeerHeight": reply.CoreData.Current_Height,
  122. "Top Version": reply.CoreData.Top_Version,
  123. "Top_ID": fmt.Sprintf("%x", reply.CoreData.Top_ID),
  124. }).Debugf("Successful Handshake with Peer")
  125. // lets check whether we need to resync with this peer
  126. if chain.IsLagging(reply.CoreData.Cumulative_Difficulty, reply.CoreData.Current_Height, reply.CoreData.Top_ID) {
  127. logger.Debugf("We need to resync with the peer")
  128. // set mode to syncronising
  129. Send_BC_Notify_Chain_Command(connection)
  130. }
  131. }