|
|
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<crypto::hash> 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) > 400 { block_list = block_list[:399] }
// 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() }
|