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.

349 lines
10 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 "bytes"
  19. import "encoding/binary"
  20. import "github.com/romana/rlog"
  21. import "github.com/deroproject/derosuite/crypto"
  22. import "github.com/deroproject/derosuite/block"
  23. // The peer triggers this it wants some blocks or txs
  24. func Handle_BC_Notify_Request_GetObjects(connection *Connection,
  25. i_command_header *Levin_Header, buf []byte) {
  26. // deserialize data header
  27. var i_data_header Levin_Data_Header // incoming data header
  28. err := i_data_header.DeSerialize(buf)
  29. if err != nil {
  30. connection.logger.Debugf("We should destroy connection here, data header cnot deserialized")
  31. connection.Exit = true
  32. return
  33. }
  34. pos := bytes.Index(buf, []byte("\x06blocks\x0a")) // at this point to
  35. if pos < 0 {
  36. rlog.Tracef(4, "NOTIFY_REQUEST_GET_OBJECTS doesnot contains blocks. Disconnect peer \n")
  37. } else { // we have some block ids, extract and serve them
  38. tmp_slice := buf[pos+8:]
  39. rlog.Tracef(4, " varint %x", tmp_slice[:8])
  40. data_length, done := Decode_Boost_Varint(tmp_slice)
  41. tmp_slice = tmp_slice[done:]
  42. if data_length == 0 {
  43. rlog.Tracef(4, "Peer says it does not have even genesis block, so disconnect")
  44. connection.Exit = true
  45. return
  46. }
  47. rlog.Tracef(4, "Data size %d", data_length)
  48. if (data_length % 32) != 0 { // sanity check
  49. rlog.Tracef(4, "We should destroy connection here, packet mismatch")
  50. connection.Exit = true
  51. return
  52. }
  53. rlog.Tracef(4, "Number of hashes %d tmp_slice %x \n", data_length/32, tmp_slice[:32])
  54. var block_list []crypto.Hash
  55. for i := uint64(0); i < data_length/32; i++ {
  56. var bhash crypto.Hash
  57. copy(bhash[:], tmp_slice[i*32:(i+1)*32])
  58. block_list = append(block_list, bhash)
  59. rlog.Tracef(4, "%2d hash %x\n", i, bhash[:])
  60. }
  61. // send each block independently
  62. /*if len(block_list) == 1 {
  63. Send_Single_Block_to_Peer(connection, block_list[0])
  64. } else*/{ // we need to send al blocks in 1 go
  65. Send_Blocks_to_Peer(connection, block_list)
  66. }
  67. }
  68. // we must give user data
  69. }
  70. func boost_serialisation_block(hash crypto.Hash) []byte {
  71. block_header := []byte{0x04, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x0a}
  72. txs_header := []byte{0x03, 0x74, 0x78, 0x73, 0x8a}
  73. bl, err := chain.Load_BL_FROM_ID(hash)
  74. _ = err
  75. if len(bl.Tx_hashes) >= 1 {
  76. block_header[0] = 0x8
  77. }
  78. block_serialized := bl.Serialize()
  79. // add a varint len
  80. buf := make([]byte, 8, 8)
  81. done := Encode_Boost_Varint(buf, uint64(len(block_serialized))) // encode length of buffer
  82. buf = buf[:done]
  83. block_header = append(block_header, buf...)
  84. block_header = append(block_header, block_serialized...)
  85. if len(bl.Tx_hashes) >= 1 {
  86. block_header = append(block_header, txs_header...)
  87. // add txs length
  88. buf := make([]byte, 8, 8)
  89. done := Encode_Boost_Varint(buf, uint64(len(bl.Tx_hashes))) // encode length of buffer
  90. buf = buf[:done]
  91. block_header = append(block_header, buf...)
  92. for i := range bl.Tx_hashes {
  93. tx, err := chain.Load_TX_FROM_ID(bl.Tx_hashes[i])
  94. if err != nil {
  95. rlog.Tracef(1, "ERR Cannot load tx from DB\n")
  96. return block_header
  97. }
  98. tx_serialized := tx.Serialize()
  99. buf := make([]byte, 8, 8)
  100. done := Encode_Boost_Varint(buf, uint64(len(tx_serialized))) // encode length of buffer
  101. buf = buf[:done]
  102. block_header = append(block_header, buf...)
  103. block_header = append(block_header, tx_serialized...)
  104. }
  105. }
  106. return block_header
  107. }
  108. func Send_Blocks_to_Peer(connection *Connection, block_list []crypto.Hash) {
  109. blocks_header := []byte{0x01, 0x11, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
  110. 0x73, 0x8c} // this is followed by a varint count of blocks
  111. trailer := []byte{0x19, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62,
  112. 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x05}
  113. buf := make([]byte, 8, 8)
  114. binary.LittleEndian.PutUint64(buf, chain.Get_Height())
  115. trailer = append(trailer, buf...)
  116. done := Encode_Boost_Varint(buf, uint64(len(block_list))) // encode length of buffer
  117. buf = buf[:done]
  118. result := append(blocks_header, buf...)
  119. for i := range block_list {
  120. block := boost_serialisation_block(block_list[i])
  121. result = append(result, block...)
  122. }
  123. result = append(result, trailer...)
  124. var o_command_header Levin_Header
  125. o_command_header.CB = uint64(len(result))
  126. o_command_header.Command = BC_NOTIFY_RESPONSE_GET_OBJECTS
  127. o_command_header.ReturnData = false
  128. o_command_header.Flags = LEVIN_PACKET_REQUEST
  129. o_command_header_bytes, _ := o_command_header.Serialize()
  130. connection.Conn.Write(o_command_header_bytes)
  131. connection.Conn.Write(result)
  132. }
  133. func Send_Single_Block_to_Peer(connection *Connection, hash crypto.Hash) {
  134. bl, err := chain.Load_BL_FROM_ID(hash)
  135. if err == nil {
  136. if len(bl.Tx_hashes) == 0 {
  137. Send_Block_with_ZERO_TX(connection, bl)
  138. } else {
  139. Send_Block_with_TX(connection, bl)
  140. }
  141. }
  142. }
  143. /*
  144. header
  145. 00009F94 01 11 01 01 01 01 02 01 01 08 06 62 6c 6f 63 6b ........ ...block
  146. 00009FA4 73 8c 04 08 05 62 6c 6f 63 6b 0a s....blo ck......
  147. trailer
  148. 000173C4 19 63 75 72 72 65 6e 74 5f 62 nm.'...c urrent_b
  149. 000173D4 6c 6f 63 6b 63 68 61 69 6e 5f 68 65 69 67 68 74 lockchai n_height
  150. 000173E4 05 ec 04 00 00 00 00 00 00
  151. */
  152. // if a block is with out TX, send it in this format
  153. func Send_Block_with_ZERO_TX(connection *Connection, bl *block.Block) {
  154. fmt.Printf("sending block with zero tx")
  155. header := []byte{0x01, 0x11, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
  156. 0x73, 0x8c, 0x04, 0x04, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x0a}
  157. trailer := []byte{0x19, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62,
  158. 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x05}
  159. buf := make([]byte, 8, 8)
  160. binary.LittleEndian.PutUint64(buf, chain.Get_Height())
  161. trailer = append(trailer, buf...)
  162. block_serialized := bl.Serialize()
  163. done := Encode_Boost_Varint(buf, uint64(len(block_serialized))) // encode length of buffer
  164. buf = buf[:done]
  165. header = append(header, buf...)
  166. header = append(header, block_serialized...)
  167. header = append(header, trailer...)
  168. var o_command_header Levin_Header
  169. o_command_header.CB = uint64(len(header))
  170. o_command_header.Command = BC_NOTIFY_RESPONSE_GET_OBJECTS
  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(header)
  176. }
  177. // if a block is with TX, send it in this format
  178. func Send_Block_with_TX(connection *Connection, bl *block.Block) {
  179. panic("Sending block with TX not implmented\n")
  180. }
  181. // header from boost packet
  182. //0060 00 00 00 01 11 01 01 01 01 02 01 [] 01 04 09 62 6c ..............bl
  183. //0070 6f 63 6b 5f 69 64 73 0a [] 81 0a 9b a2 3e fe 50 5f ock_ids.....>.P_
  184. // send the peer the blocks hash and transactions hash, that we need
  185. // this function, splits the request and serves
  186. // we split the request into 2 requests
  187. func Send_BC_Notify_Request_GetObjects(connection *Connection, block_list []crypto.Hash, tx_list []crypto.Hash) {
  188. connection.Lock()
  189. txs_header_bytes := []byte{0x03, 't', 'x', 's', 0x0a}
  190. blocks_header_bytes := []byte{0x06, 'b', 'l', 'o', 'c', 'k', 's', 0x0a}
  191. // now append boost variant length, and then append all the hashes
  192. // add your blocks here
  193. // adding genesis block
  194. //block_list = append(block_list,globals.Config.Genesis_Block_Hash)
  195. /*for i := 0; i < 100;i++{
  196. block_list = append(block_list,globals.Config.Genesis_Block_Hash)
  197. }*/
  198. // split block request in independent request , so the response comes independent
  199. if len(block_list) > 0 {
  200. rlog.Tracef(4, "Sending block request for %d blocks \n", len(block_list))
  201. for i := range block_list {
  202. buf := make([]byte, 8, 8)
  203. done := Encode_Boost_Varint(buf, uint64(32)) // encode length of buffer
  204. buf = buf[:done]
  205. var o_command_header Levin_Header
  206. var o_data_header Levin_Data_Header
  207. o_data_header.Data = append(blocks_header_bytes, buf...)
  208. // convert and append all hashes to bytes
  209. o_data_header.Data = append(o_data_header.Data, block_list[i][:32]...)
  210. o_data_bytes, _ := o_data_header.Serialize()
  211. o_data_bytes[9] = 0x4
  212. o_command_header.CB = uint64(len(o_data_bytes))
  213. o_command_header.Command = BC_NOTIFY_REQUEST_GET_OBJECTS
  214. o_command_header.ReturnData = false
  215. o_command_header.Flags = LEVIN_PACKET_REQUEST
  216. o_command_header_bytes, _ := o_command_header.Serialize()
  217. connection.Conn.Write(o_command_header_bytes)
  218. connection.Conn.Write(o_data_bytes)
  219. }
  220. }
  221. if len(tx_list) > 0 {
  222. rlog.Tracef(4, "Sending tx request for %d tx \n", len(tx_list))
  223. buf := make([]byte, 8, 8)
  224. done := Encode_Boost_Varint(buf, uint64(len(tx_list)*32)) // encode length of buffer
  225. buf = buf[:done]
  226. var o_command_header Levin_Header
  227. var o_data_header Levin_Data_Header
  228. o_data_header.Data = append(txs_header_bytes, buf...)
  229. // convert and append all hashes to bytes
  230. for _, hash := range tx_list {
  231. o_data_header.Data = append(o_data_header.Data, hash[:32]...)
  232. }
  233. o_data_bytes, _ := o_data_header.Serialize()
  234. o_data_bytes[9] = 0x4
  235. o_command_header.CB = uint64(len(o_data_bytes))
  236. o_command_header.Command = BC_NOTIFY_REQUEST_GET_OBJECTS
  237. o_command_header.ReturnData = false
  238. o_command_header.Flags = LEVIN_PACKET_REQUEST
  239. o_command_header_bytes, _ := o_command_header.Serialize()
  240. connection.Conn.Write(o_command_header_bytes)
  241. connection.Conn.Write(o_data_bytes)
  242. }
  243. //fmt.Printf("len of command header %d\n", len(o_command_header_bytes))
  244. //fmt.Printf("len of data header %d\n", len(o_data_bytes))
  245. connection.Unlock()
  246. }