// Copyright 2017-2018 DERO Project. All rights reserved. // Use of this source code in any form is governed by RESEARCH license. // license can be found in the LICENSE file. // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 // // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package p2p import "bytes" import "encoding/binary" import "github.com/romana/rlog" import "github.com/deroproject/derosuite/globals" import "github.com/deroproject/derosuite/crypto" /* the data structure which needs to be serialised is defined in cryptonote_protocol_defs.h * struct request { uint64_t start_height; uint64_t total_height; uint64_t cumulative_difficulty; std::list m_block_ids; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(cumulative_difficulty) KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_ids) KV_SERIALIZE(start_height) KV_SERIALIZE(total_height) END_KV_SERIALIZE_MAP() }; */ // This request only comes when we have sent the BC_NOTIFY_REQUEST_CHAIN command // handle BC_NOTIFY_RESPONSE_CHAIN_ENTRY func Handle_BC_Notify_Response_Chain_Entry(connection *Connection, i_command_header *Levin_Header, buf []byte) { // deserialize data header var i_data_header Levin_Data_Header // incoming data header err := i_data_header.DeSerialize(buf) if err != nil { //fmt.Printf("We should destroy connection here, data header cnot deserialized") rlog.Tracef(4, "Data header deserialisation failed. Disconnect peer \n") connection.Exit = true return } pos := bytes.Index(i_data_header.Data, []byte("cumulative_difficulty")) // at this point to if pos == -1 { rlog.Tracef(4, "Cumulative difficulty deserialisation failed. Disconnect peer \n") connection.Exit = true return } cumulative_difficulty := binary.LittleEndian.Uint64(i_data_header.Data[pos+22:]) rlog.Tracef(4, "Cumalative difficulty %d %x\n", cumulative_difficulty, cumulative_difficulty) pos = bytes.Index(i_data_header.Data, []byte("start_height")) // at this point to if pos == -1 { panic("start_height not found, its mandatory\n") } start_height := binary.LittleEndian.Uint64(i_data_header.Data[pos+13:]) rlog.Tracef(4, "start_height %d %x\n", start_height, start_height) pos = bytes.Index(i_data_header.Data, []byte("m_block_ids")) // at this point to if pos == -1 { panic("m_block_ids not found, its mandatory\n") } // decode data length ( though we know it from buffer size, but still verify it ) buf = i_data_header.Data[pos+11+1:] data_length, done := Decode_Boost_Varint(buf) //fmt.Printf("data length %d , hex %x\n", data_length, buf[:8]) buf = buf[done:] if data_length == 0 { rlog.Tracef(4, "Peer says it does not have even genesis block, so disconnect") connection.Exit = true return } if (data_length % 32) != 0 { // sanity check rlog.Tracef(2, "We should destroy connection here, packet mismatch") connection.Exit = true return } rlog.Tracef(4, "Number of Blocks id in chain BC_NOTIFY_RESPONSE_CHAIN_ENTRY %d \n", data_length/32) var block_list []crypto.Hash for i := uint64(0); i < data_length/32; i++ { var bhash crypto.Hash copy(bhash[:], buf[i*32:(i+1)*32]) // only request block that we donot have if chain.Get_Height() < 20 { block_list = append(block_list, bhash) rlog.Tracef(5, "%2d hash %x\n", i, bhash[:]) } else { if !chain.Block_Exists(bhash) { block_list = append(block_list, bhash) rlog.Tracef(5, "%2d hash %x\n", i, bhash[:]) } } } // server will kill us, if we queue more than 1000 blocks if len(block_list) > 900 { block_list = block_list[:899] } // make sure the genesis block is same // if peer provided us a genesis block make sure, its ours if start_height == 0 && block_list[0] != globals.Config.Genesis_Block_Hash { rlog.Tracef(4, "Peer's genesis block is different from our, so disconnect") connection.Exit = true return } // we must queue the hashes so as to fetch them //block_list = block_list[:0] var hash crypto.Hash /* //big_block ,_ := hex.DecodeString("9ba23efe505f9674dc24c150edbdbe57abc3ec6636aa4c1659e811b389c0b30b") // zero tx //big_block ,_ := hex.DecodeString("14371eeddca0f3ce9b992b3e2a0e482920497d87dd20002456f3a844b04a3318") // single tx big_block ,_ := hex.DecodeString("a31a17bb26b2ec37479ee3a02f53dd94860611457811d0c23ce892f4e87e1697") // 4 tx copy(hash[:],big_block[:32]) block_list = append(block_list, hash) big_tx, _ := hex.DecodeString("af6f12d56f32f58623a834c4f12c5443976346a2f877ef78798c39496bd00559") // single tx var tx_list []ringct.Hash copy(hash[:],big_tx[:32]) tx_list = append(tx_list, hash) */ _ = hash var tx_list []crypto.Hash /*if len(block_list) > 5 { block_list= block_list[:5] }*/ Send_BC_Notify_Request_GetObjects(connection, block_list, tx_list[:0]) } // header from boost packet /* header bytes 0000 01 11 01 01 01 01 02 01 01 10 15 63 75 6d 75 6c ...........cumul 0010 61 74 69 76 65 5f 64 69 66 66 69 63 75 6c 74 79 ative_difficulty 0020 05 ab 61 00 00 00 00 00 00 0b 6d 5f 62 6c 6f 63 ..a.......m_bloc 0030 6b 5f 69 64 73 0a 82 72 02 00 63 34 12 de 21 ea k_ids..r..c4..!. // suffix_bytes 44d0 4c 16 59 e8 11 b3 89 c0 b3 0b 0c 73 74 61 72 74 L.Y........start 44e0 5f 68 65 69 67 68 74 05 00 00 00 00 00 00 00 00 _height......... 44f0 0c 74 6f 74 61 6c 5f 68 65 69 67 68 74 05 e5 04 .total_height... 4500 00 00 00 00 00 00 ...... */ // send the PEER the blocks he needs to download our version of chain // this is send every 5 seconds func Send_BC_Notify_Response_Chain_Entry(connection *Connection, block_list []crypto.Hash, start_height, current_height, diff uint64) { connection.Lock() header_bytes := []byte{0x01, 0x11, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x10, 0x15, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x05, 0xab, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x6d, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x0a} suffix_bytes := []byte{0x0c, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x05, 0xe5, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} binary.LittleEndian.PutUint64(header_bytes[33:], diff) binary.LittleEndian.PutUint64(suffix_bytes[14:], start_height) binary.LittleEndian.PutUint64(suffix_bytes[36:], current_height) // now append boost variant length, and then append all the hashes buf := make([]byte, 8, 8) done := Encode_Boost_Varint(buf, uint64(len(block_list)*32)) // encode length of buffer buf = buf[:done] var o_command_header Levin_Header data_bytes := append(header_bytes, buf...) // convert and append all hashes to bytes for _, hash := range block_list { data_bytes = append(data_bytes, hash[:32]...) } data_bytes = append(data_bytes, suffix_bytes...) o_command_header.CB = uint64(len(data_bytes)) o_command_header.Command = BC_NOTIFY_RESPONSE_CHAIN_ENTRY o_command_header.ReturnData = false o_command_header.Flags = LEVIN_PACKET_REQUEST o_command_header_bytes, _ := o_command_header.Serialize() connection.Conn.Write(o_command_header_bytes) connection.Conn.Write(data_bytes) //fmt.Printf("len of command header %d\n", len(o_command_header_bytes)) //fmt.Printf("len of data header %d\n", len(data_bytes)) connection.Unlock() }