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.

337 lines
9.5 KiB

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