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.

240 lines
8.1 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 "bytes"
  18. import "encoding/binary"
  19. import "github.com/romana/rlog"
  20. import "github.com/deroproject/derosuite/globals"
  21. import "github.com/deroproject/derosuite/crypto"
  22. /* the data structure which needs to be serialised is defined in cryptonote_protocol_defs.h
  23. * struct request
  24. {
  25. uint64_t start_height;
  26. uint64_t total_height;
  27. uint64_t cumulative_difficulty;
  28. std::list<crypto::hash> m_block_ids;
  29. BEGIN_KV_SERIALIZE_MAP()
  30. KV_SERIALIZE(cumulative_difficulty)
  31. KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_ids)
  32. KV_SERIALIZE(start_height)
  33. KV_SERIALIZE(total_height)
  34. END_KV_SERIALIZE_MAP()
  35. };
  36. */
  37. // This request only comes when we have sent the BC_NOTIFY_REQUEST_CHAIN command
  38. // handle BC_NOTIFY_RESPONSE_CHAIN_ENTRY
  39. func Handle_BC_Notify_Response_Chain_Entry(connection *Connection,
  40. i_command_header *Levin_Header, buf []byte) {
  41. // deserialize data header
  42. var i_data_header Levin_Data_Header // incoming data header
  43. err := i_data_header.DeSerialize(buf)
  44. if err != nil {
  45. //fmt.Printf("We should destroy connection here, data header cnot deserialized")
  46. rlog.Tracef(4, "Data header deserialisation failed. Disconnect peer \n")
  47. connection.Exit = true
  48. return
  49. }
  50. pos := bytes.Index(i_data_header.Data, []byte("cumulative_difficulty")) // at this point to
  51. if pos == -1 {
  52. rlog.Tracef(4, "Cumulative difficulty deserialisation failed. Disconnect peer \n")
  53. connection.Exit = true
  54. return
  55. }
  56. cumulative_difficulty := binary.LittleEndian.Uint64(i_data_header.Data[pos+22:])
  57. rlog.Tracef(4, "Cumalative difficulty %d %x\n", cumulative_difficulty, cumulative_difficulty)
  58. pos = bytes.Index(i_data_header.Data, []byte("start_height")) // at this point to
  59. if pos == -1 {
  60. panic("start_height not found, its mandatory\n")
  61. }
  62. start_height := binary.LittleEndian.Uint64(i_data_header.Data[pos+13:])
  63. rlog.Tracef(4, "start_height %d %x\n", start_height, start_height)
  64. pos = bytes.Index(i_data_header.Data, []byte("m_block_ids")) // at this point to
  65. if pos == -1 {
  66. panic("m_block_ids not found, its mandatory\n")
  67. }
  68. // decode data length ( though we know it from buffer size, but still verify it )
  69. buf = i_data_header.Data[pos+11+1:]
  70. data_length, done := Decode_Boost_Varint(buf)
  71. //fmt.Printf("data length %d , hex %x\n", data_length, buf[:8])
  72. buf = buf[done:]
  73. if data_length == 0 {
  74. rlog.Tracef(4, "Peer says it does not have even genesis block, so disconnect")
  75. connection.Exit = true
  76. return
  77. }
  78. if (data_length % 32) != 0 { // sanity check
  79. rlog.Tracef(2, "We should destroy connection here, packet mismatch")
  80. connection.Exit = true
  81. return
  82. }
  83. rlog.Tracef(4, "Number of Blocks id in chain BC_NOTIFY_RESPONSE_CHAIN_ENTRY %d \n", data_length/32)
  84. var block_list []crypto.Hash
  85. for i := uint64(0); i < data_length/32; i++ {
  86. var bhash crypto.Hash
  87. copy(bhash[:], buf[i*32:(i+1)*32])
  88. // only request block that we donot have
  89. if chain.Get_Height() < 20 {
  90. block_list = append(block_list, bhash)
  91. rlog.Tracef(5, "%2d hash %x\n", i, bhash[:])
  92. } else {
  93. if !chain.Block_Exists(bhash) {
  94. block_list = append(block_list, bhash)
  95. rlog.Tracef(5, "%2d hash %x\n", i, bhash[:])
  96. }
  97. }
  98. }
  99. // server will kill us, if we queue more than 1000 blocks
  100. if len(block_list) > 900 {
  101. block_list = block_list[:899]
  102. }
  103. // make sure the genesis block is same
  104. // if peer provided us a genesis block make sure, its ours
  105. if start_height == 0 && block_list[0] != globals.Config.Genesis_Block_Hash {
  106. rlog.Tracef(4, "Peer's genesis block is different from our, so disconnect")
  107. connection.Exit = true
  108. return
  109. }
  110. // we must queue the hashes so as to fetch them
  111. //block_list = block_list[:0]
  112. var hash crypto.Hash
  113. /*
  114. //big_block ,_ := hex.DecodeString("9ba23efe505f9674dc24c150edbdbe57abc3ec6636aa4c1659e811b389c0b30b") // zero tx
  115. //big_block ,_ := hex.DecodeString("14371eeddca0f3ce9b992b3e2a0e482920497d87dd20002456f3a844b04a3318") // single tx
  116. big_block ,_ := hex.DecodeString("a31a17bb26b2ec37479ee3a02f53dd94860611457811d0c23ce892f4e87e1697") // 4 tx
  117. copy(hash[:],big_block[:32])
  118. block_list = append(block_list, hash)
  119. big_tx, _ := hex.DecodeString("af6f12d56f32f58623a834c4f12c5443976346a2f877ef78798c39496bd00559") // single tx
  120. var tx_list []ringct.Hash
  121. copy(hash[:],big_tx[:32])
  122. tx_list = append(tx_list, hash)
  123. */
  124. _ = hash
  125. var tx_list []crypto.Hash
  126. /*if len(block_list) > 5 {
  127. block_list= block_list[:5]
  128. }*/
  129. Send_BC_Notify_Request_GetObjects(connection, block_list, tx_list[:0])
  130. }
  131. // header from boost packet
  132. /* header bytes
  133. 0000 01 11 01 01 01 01 02 01 01 10 15 63 75 6d 75 6c ...........cumul
  134. 0010 61 74 69 76 65 5f 64 69 66 66 69 63 75 6c 74 79 ative_difficulty
  135. 0020 05 ab 61 00 00 00 00 00 00 0b 6d 5f 62 6c 6f 63 ..a.......m_bloc
  136. 0030 6b 5f 69 64 73 0a 82 72 02 00 63 34 12 de 21 ea k_ids..r..c4..!.
  137. // suffix_bytes
  138. 44d0 4c 16 59 e8 11 b3 89 c0 b3 0b 0c 73 74 61 72 74 L.Y........start
  139. 44e0 5f 68 65 69 67 68 74 05 00 00 00 00 00 00 00 00 _height.........
  140. 44f0 0c 74 6f 74 61 6c 5f 68 65 69 67 68 74 05 e5 04 .total_height...
  141. 4500 00 00 00 00 00 00 ......
  142. */
  143. // send the PEER the blocks he needs to download our version of chain
  144. // this is send every 5 seconds
  145. func Send_BC_Notify_Response_Chain_Entry(connection *Connection, block_list []crypto.Hash, start_height, current_height, diff uint64) {
  146. connection.Lock()
  147. header_bytes := []byte{0x01, 0x11, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x10, 0x15, 0x63, 0x75, 0x6d, 0x75, 0x6c,
  148. 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79,
  149. 0x05, 0xab, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x6d, 0x5f, 0x62, 0x6c, 0x6f, 0x63,
  150. 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x0a}
  151. suffix_bytes := []byte{0x0c, 0x73, 0x74, 0x61, 0x72, 0x74,
  152. 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  153. 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x05, 0xe5, 0x04,
  154. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
  155. binary.LittleEndian.PutUint64(header_bytes[33:], diff)
  156. binary.LittleEndian.PutUint64(suffix_bytes[14:], start_height)
  157. binary.LittleEndian.PutUint64(suffix_bytes[36:], current_height)
  158. // now append boost variant length, and then append all the hashes
  159. buf := make([]byte, 8, 8)
  160. done := Encode_Boost_Varint(buf, uint64(len(block_list)*32)) // encode length of buffer
  161. buf = buf[:done]
  162. var o_command_header Levin_Header
  163. data_bytes := append(header_bytes, buf...)
  164. // convert and append all hashes to bytes
  165. for _, hash := range block_list {
  166. data_bytes = append(data_bytes, hash[:32]...)
  167. }
  168. data_bytes = append(data_bytes, suffix_bytes...)
  169. o_command_header.CB = uint64(len(data_bytes))
  170. o_command_header.Command = BC_NOTIFY_RESPONSE_CHAIN_ENTRY
  171. o_command_header.ReturnData = false
  172. o_command_header.Flags = LEVIN_PACKET_REQUEST
  173. o_command_header_bytes, _ := o_command_header.Serialize()
  174. connection.Conn.Write(o_command_header_bytes)
  175. connection.Conn.Write(data_bytes)
  176. //fmt.Printf("len of command header %d\n", len(o_command_header_bytes))
  177. //fmt.Printf("len of data header %d\n", len(data_bytes))
  178. connection.Unlock()
  179. }