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.

142 lines
4.5 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/arnaucode/derosuite/block"
  21. import "github.com/arnaucode/derosuite/transaction"
  22. // FIXME this code can also be shared by NOTIFY_NEW_BLOCK, NOTIFY_NEW_TRANSACTIONS, Handle_BC_Notify_Response_GetObjects
  23. // this code handles a new block floating in the network
  24. func Handle_BC_Notify_New_Block(connection *Connection,
  25. i_command_header *Levin_Header, buf []byte) {
  26. var bl block.Block
  27. var cbl block.Complete_Block
  28. connection.logger.Debugf("Incoming NOTIFY_NEW_BLOCK")
  29. // deserialize data header
  30. var i_data_header Levin_Data_Header // incoming data header
  31. err := i_data_header.DeSerialize(buf)
  32. if err != nil {
  33. connection.logger.Debugf("We should destroy connection here, data header cnot deserialized")
  34. return
  35. }
  36. buf = i_data_header.Data
  37. pos := bytes.Index(buf, []byte("block"))
  38. // find inner position of block
  39. pos = pos + 6 // jump to varint length position and decode
  40. buf = buf[pos:]
  41. block_length, done := Decode_Boost_Varint(buf)
  42. rlog.Tracef(2, "Block length %d %x\n", block_length, buf[:8])
  43. buf = buf[done:]
  44. block_buf := buf[:block_length]
  45. err = bl.Deserialize(block_buf)
  46. if err != nil {
  47. connection.logger.Warnf("Block could not be deserialized successfully err %s\n", err)
  48. connection.logger.Debugf("We should destroy connection here, block not deserialized")
  49. return
  50. }
  51. hash := bl.GetHash()
  52. rlog.Tracef(1, "Block deserialized successfully %x\n", hash[:32])
  53. rlog.Tracef(1, "Tx hash length %d\n", len(bl.Tx_hashes))
  54. for i := range bl.Tx_hashes {
  55. rlog.Tracef(2, "%d tx %x\n", i, bl.Tx_hashes[i][:32])
  56. }
  57. // point buffer to check whether any more tx exist
  58. buf = buf[block_length:]
  59. pos = bytes.Index(buf, []byte("\x03txs\x8a")) // at this point to
  60. if pos > -1 {
  61. rlog.Tracef(3, "txt pos %d\n", pos)
  62. buf = buf[pos+5:]
  63. // decode remain data length ( though we know it from buffer size, but still verify it )
  64. tx_count, done := Decode_Boost_Varint(buf)
  65. buf = buf[done:]
  66. for i := uint64(0); i < tx_count; i++ {
  67. var tx transaction.Transaction
  68. tx_len, done := Decode_Boost_Varint(buf)
  69. buf = buf[done:]
  70. rlog.Tracef(3, "tx count %d i %d tx_len %d\n", tx_count, i, tx_len)
  71. tx_bytes := buf[:tx_len]
  72. // deserialize and verrify transaction
  73. err = tx.DeserializeHeader(tx_bytes)
  74. if err != nil {
  75. connection.logger.Warnf("Transaction could not be deserialized\n")
  76. } else {
  77. hash := tx.GetHash()
  78. rlog.Tracef(2, "Transaction deserialised successfully hash %x\n", hash[:32])
  79. // add tx to block chain, we must verify that the tx has been mined
  80. // add all transaction to TX pool , if not added
  81. //chain.Add_TX(&tx)
  82. cbl.Txs = append(cbl.Txs, &tx)
  83. }
  84. buf = buf[tx_len:] // setup for next tx
  85. }
  86. }
  87. height_string := []byte("\x19current_blockchain_height\x05")
  88. pos = bytes.Index(buf, height_string) // at this point to
  89. if pos < 0 {
  90. connection.logger.Debugf("We should destroy connection here, block not deserialized")
  91. return
  92. }
  93. pos = pos + len(height_string)
  94. buf = buf[pos:]
  95. current_peer_height := binary.LittleEndian.Uint64(buf)
  96. connection.Last_Height = current_peer_height
  97. //connection.logger.Infof("buffer height %x current height %d complete %d\n", buf, connection.Last_Height, complete_block)
  98. // at this point, if it's a block we should try to add it to block chain
  99. // try to add block to chain
  100. connection.logger.Debugf("Found new block adding it to chain %s", bl.GetHash())
  101. // TODO check returned status, either drop connection or replay
  102. cbl.Bl = &bl
  103. chain.Add_Complete_Block(&cbl)
  104. }