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.

118 lines
4.6 KiB

// 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 p2pv2
import "net"
import "encoding/binary"
// This file defines the structure for the protocol which is a msgp encoded ( which is standard)
// msgp would cause an easy rewrite of p2p layer even in c, ruby or rust etc as future may demand
// the protocol is length prefixed msgp payload
// though we can use http2 stream features, they may become compilcated as the project evolve
// the prefix length is 4 bytes, little endian encoded ( so a frame can be 4GB in size)
// this is Work-In-Progress
// the reason for writing it from scratch is the mess of boost serialisation
// the p2p package is currently the most complex within the entire project
// the protocol is partly syncronous, partly asyncronous , except for first handshake, so the node remain undetectable to external network scans, the detection cost is to atleast send a handshake packet*/
// these are the commands required to make it completely operational
const V2_COMMAND_HANDSHAKE = 1 // commands are syncronous and must be responded within 10 secs
const V2_COMMAND_SYNC = 2
const V2_COMMAND_CHAIN_REQUEST = 3
const V2_COMMAND_CHAIN_RESPONSE = 4
const V2_COMMAND_OBJECTS_REQUEST = 5
const V2_COMMAND_OBJECTS_RESPONSE = 6
const V2_NOTIFY_NEW_BLOCK = 0x80000000 // Notifications are asyncronous all notifications come here, such as new block, new txs
const V2_NOTIFY_NEW_TX = 0x80000001 // notify tx using this
// used to parse incoming packet for for command , so as a repective command command could be triggered
type Common struct {
Command uint64 `msgpack:"C"`
Height uint64 `msgpack:"H"`
Cumulative_Difficulty uint64 `msgpack:"CD"`
Top_ID [32]byte `msgpack:"TI"` // 32 bytes of Top block
Top_Version uint64 `msgpack:"TV"` // this basically represents the hard fork version
}
// at start, client sends handshake and server will respond to handshake
type Handshake struct {
Common // add all fields of Common
Local_Time int64 `msgpack:"LT"`
Local_Port uint32 `msgpack:"LP"`
PeerID uint64 `msgpack:"PID"`
Network_ID [16]byte `msgpack:"NID"` // 16 bytes
PeerList []Peer_Info `msgpack:"PLIST"`
Extension_List []string `msgpack:"EXT"`
Request bool `msgpack:"REQUEST"` //whether this is a request
}
type Peer_Info struct {
IP net.IP `msgpack:"IP"`
Port uint32 `msgpack:"P"`
ID uint64 `msgpack:"I"`
LastSeen uint64 `msgpack:"LS"`
}
type Sync struct {
Common // add all fields of common
}
type Chain_Request struct {
Block_list [][32]byte `msgpack:"BLIST"`
}
type Chain_Response struct {
Start_height uint64 `msgpack:"SH"`
Block_list [][32]byte `msgpack:"BLIST"`
}
type Object_Request struct {
Block_list [][32]byte `msgpack:"BLIST"`
Tx_list [][32]byte `msgpack:"TXLIST"`
}
type Complete_Block struct {
Block []byte `msgpack:"BLOCK"`
Txs [][]byte `msgpack:"TXS"`
}
type Object_Response struct {
Blocks []Complete_Block `msgpack:"CBLOCKS"`
Txs [][]byte `msgpack:"TXS"`
}
type Notify_New_Objects struct {
Block Complete_Block `msgpack:"CBLOCK"`
Txs [][]byte `msgpack:"TXS"`
}
// each packet has to be parsed twice once for extracting command and then a full parsing
// the message is sent as follows
// assumingin peer lock has already been taken
func (conn *Connection) Send_Message(data_bytes []byte) {
var length_bytes [4]byte
binary.LittleEndian.PutUint32(length_bytes[:], uint32(len(data_bytes)))
// send the length prefix
conn.Conn.Write(length_bytes[:])
conn.Conn.Write(data_bytes) // send the message itself
}