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.

178 lines
5.0 KiB

  1. package p2p
  2. import "github.com/romana/rlog"
  3. import "github.com/deroproject/derosuite/globals"
  4. import "github.com/deroproject/derosuite/crypto"
  5. // when 2 peers communiate either both are in sync or async
  6. // if async, reply to the request below, with your state and other will supply you list of block ids
  7. // handle BC_NOTIFY_REQUEST_CHAIN
  8. func Handle_BC_Notify_Chain(connection *Connection,
  9. i_command_header *Levin_Header, buf []byte) {
  10. // deserialize data header
  11. var i_data_header Levin_Data_Header // incoming data header
  12. err := i_data_header.DeSerialize(buf)
  13. if err != nil {
  14. connection.logger.Debugf("We should destroy connection here, data header cnot deserialized")
  15. connection.Exit = true
  16. return
  17. }
  18. buf = i_data_header.Data[11:] // 11 bytes boost header, ignore it
  19. // decode remain data length ( though we know it from buffer size, but still verify it )
  20. data_length, done := Decode_Boost_Varint(buf)
  21. buf = buf[done:]
  22. if data_length == 0 {
  23. rlog.Tracef(4, "Peer says it does not have even genesis block, so disconnect")
  24. connection.Exit = true
  25. return
  26. }
  27. if (data_length % 32) != 0 { // sanity check
  28. rlog.Tracef(4, "We should destroy connection here, packet mismatch")
  29. connection.Exit = true
  30. return
  31. }
  32. rlog.Tracef(4, "Number of hashes %d \n", data_length/32)
  33. var block_list []crypto.Hash
  34. for i := uint64(0); i < data_length/32; i++ {
  35. var bhash crypto.Hash
  36. copy(bhash[:], buf[i*32:(i+1)*32])
  37. block_list = append(block_list, bhash)
  38. rlog.Tracef(5,"%2d hash %x\n", i, bhash[:])
  39. }
  40. // the data is like this, first 10 blocks, then block are in 2^n power and the last block is genesis
  41. // make sure the genesis block is same
  42. if block_list[len(block_list)-1] != globals.Config.Genesis_Block_Hash {
  43. connection.logger.Debugf("Peer's genesis block is different from our, so disconnect")
  44. connection.Exit = true
  45. return
  46. }
  47. // we must give user our version of the chain
  48. start_height := uint64(0)
  49. for i := 0; i < len(block_list); i++ { // find the common point in our chain
  50. if chain.Block_Exists(block_list[i]) {
  51. start_height = chain.Load_Height_for_BL_ID(block_list[i])
  52. rlog.Tracef(4,"Found common point in chain at hash %x\n", block_list[i])
  53. break
  54. }
  55. }
  56. // send atleast 16001 block or till the top
  57. stop_height := chain.Get_Height()
  58. if (stop_height - start_height) > 1001 { // send MAX 512 KB block hashes
  59. stop_height = start_height + 1002
  60. }
  61. block_list = block_list[:0]
  62. for i := start_height; i < stop_height; i++ {
  63. hash, _ := chain.Load_BL_ID_at_Height(i)
  64. block_list = append(block_list, hash)
  65. }
  66. rlog.Tracef(2,"Prepared list of %d block header to send \n", len(block_list))
  67. Send_BC_Notify_Response_Chain_Entry(connection, block_list, start_height, chain.Get_Height(), 1)
  68. }
  69. // header from boost packet
  70. //0060 00 00 00 01 11 01 01 01 01 02 01 [] 01 04 09 62 6c ..............bl
  71. //0070 6f 63 6b 5f 69 64 73 0a [] 81 0a 9b a2 3e fe 50 5f ock_ids.....>.P_
  72. // send the Peer our chain status, so he can give us the latest chain or updated block_ids
  73. // this is only sent when we are in different from peers
  74. func Send_BC_Notify_Chain_Command(connection *Connection) {
  75. connection.Lock()
  76. header_bytes := []byte{ /*0x01, 0x04,*/ 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x0a}
  77. _ = header_bytes
  78. // now append boost variant length, and then append all the hashes
  79. var block_list []crypto.Hash
  80. // add your blocks here
  81. our_height := chain.Get_Height()
  82. if our_height < 20 { // if height is less than 20, fetch from genesis block
  83. } else { // send blocks in reverse
  84. for i := uint64(1); our_height < 11; i++ {
  85. hash, err := chain.Load_BL_ID_at_Height(our_height - i)
  86. _ = err
  87. block_list = append(block_list, hash)
  88. }
  89. our_height = our_height - 11
  90. // now seend all our block id in log, 2nd, 4th, 8th, etc
  91. for ; our_height > 0; our_height = our_height >> 1 {
  92. hash, err := chain.Load_BL_ID_at_Height(our_height)
  93. _ = err
  94. block_list = append(block_list, hash)
  95. }
  96. }
  97. // final block is always genesis block
  98. block_list = append(block_list, globals.Config.Genesis_Block_Hash)
  99. buf := make([]byte, 8, 8)
  100. done := Encode_Boost_Varint(buf, uint64(len(block_list)*32)) // encode length of buffer
  101. buf = buf[:done]
  102. var o_command_header Levin_Header
  103. var o_data_header Levin_Data_Header
  104. o_data_header.Data = append(header_bytes, buf...)
  105. // convert and append all hashes to bytes
  106. for _, hash := range block_list {
  107. o_data_header.Data = append(o_data_header.Data, hash[:32]...)
  108. }
  109. o_data_bytes, _ := o_data_header.Serialize()
  110. o_data_bytes[9] = 0x4
  111. o_command_header.CB = uint64(len(o_data_bytes))
  112. o_command_header.Command = BC_NOTIFY_REQUEST_CHAIN
  113. o_command_header.ReturnData = false
  114. o_command_header.Flags = LEVIN_PACKET_REQUEST
  115. o_command_header_bytes, _ := o_command_header.Serialize()
  116. connection.Conn.Write(o_command_header_bytes)
  117. connection.Conn.Write(o_data_bytes)
  118. //fmt.Printf("len of command header %d\n", len(o_command_header_bytes))
  119. //fmt.Printf("len of data header %d\n", len(o_data_bytes))
  120. connection.Unlock()
  121. }