protocol

package
v0.0.0-...-23397e3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2023 License: MIT Imports: 15 Imported by: 2

README

Protocol

The Peernet Protocol is defined in the Whitepaper and implemented here accordingly.

Documentation

Index

Constants

View Source
const (
	// Peer List Management
	CommandAnnouncement   = 0 // Announcement
	CommandResponse       = 1 // Response
	CommandPing           = 2 // Keep-alive message (no payload).
	CommandPong           = 3 // Response to ping (no payload).
	CommandLocalDiscovery = 4 // Local discovery
	CommandTraverse       = 5 // Help establish a connection between 2 remote peers

	// Blockchain
	CommandGetBlock = 6 // Request blocks for specified peer.

	// File Discovery
	CommandTransfer = 8 // File transfer.

	// Debug
	CommandChat = 10 // Chat message [debug]
)

Commands between peers

View Source
const (
	FeatureIPv4Listen = 0 // Sender listens on IPv4
	FeatureIPv6Listen = 1 // Sender listens on IPv6
	FeatureFirewall   = 2 // Sender indicates a potential firewall. This informs uncontacted peers that a Traverse message might be required to establish a connection.
)

Features are sent as bit array in the Announcement message.

View Source
const (
	ActionFindSelf  = 0 // FIND_SELF Request closest neighbors to self
	ActionFindPeer  = 1 // FIND_PEER Request closest neighbors to target peer
	ActionFindValue = 2 // FIND_VALUE Request data or closest peers
	ActionInfoStore = 3 // INFO_STORE Sender indicates storing provided data
)

Actions between peers, sent via Announcement message. They correspond to the bit array index.

View Source
const (
	GetBlockControlRequestStart = 0 // Request start transfer of blocks
	GetBlockControlNotAvailable = 1 // Requested blockchain not available (not found)
	GetBlockControlActive       = 2 // Active block transfer
	GetBlockControlTerminate    = 3 // Terminate
	GetBlockControlEmpty        = 4 // Requested blockchain has 0 blocks
)
View Source
const (
	GetBlockStatusAvailable    = 0
	GetBlockStatusNotAvailable = 1
	GetBlockStatusSizeExceed   = 2
)
View Source
const (
	TransferControlRequestStart = 0 // Request start transfer of file. Data at byte 34 is offset and limit to read, each 8 bytes. Limit may be 0 to indicate entire file.
	TransferControlNotAvailable = 1 // Requested file not available
	TransferControlActive       = 2 // Active file transfer
	TransferControlTerminate    = 3 // Terminate
)
View Source
const (
	ActionSequenceLast = 0 // SEQUENCE_LAST Last response to the announcement in the sequence
)

Actions in Response message

View Source
const EmbeddedFileSizeMax = udpMaxPacketSize - PacketLengthMin - announcementPayloadHeaderSize - 2 - 35

EmbeddedFileSizeMax is the maximum size of embedded files in response messages. Any file exceeding that must be shared via regular file transfer.

View Source
const HashSize = 32

HashSize is blake3 hash digest size = 256 bits

View Source
const PacketLengthMin = 12 + signatureSize

The minimum packet size is 12 bytes (minimum header size) + 65 bytes (signature)

View Source
const PacketLiteSizeMin = 16 + 2

Minimum packet size of lite packets.

View Source
const ProtocolVersion = 0

ProtocolVersion is the current protocol version

View Source
const TransferMaxEmbedSize = internetSafeMTU - PacketLengthMin - transferPayloadHeaderSize

TransferMaxEmbedSize is a recommended default upper size of embedded data inside the Transfer message, to be used as MaxPacketSize limit in the embedded protocol. This value is chosen as the lowest denominator of different environments (IPv4, IPv6, Ethernet, Internet) for safe transfer, not for highest performance. The caller may send bigger payloads but may risk that data packets are simply dropped and never arrive. A MTU negotiation or detection could pimp that.

View Source
const TransferMaxEmbedSizeLite = internetSafeMTU - PacketLiteSizeMin

Same as TransferMaxEmbedSize but for encoding via lite packets.

View Source
const (
	TransferProtocolUDT = 0 // UDT via lite packets. No encryption.
)

Variables

This section is empty.

Functions

func BlockTransferWriteHeader

func BlockTransferWriteHeader(writer io.Writer, availability uint8, targetBlock BlockRange, blockSize uint64) (err error)

BlockTransferWriteHeader starts writing the header for a block transfer.

func EncodeAnnouncement

func EncodeAnnouncement(sendUA, findSelf bool, findPeer []KeyHash, findValue []KeyHash, files []InfoStore, features byte, blockchainHeight, blockchainVersion uint64, userAgent string) (packetsRaw [][]byte)

EncodeAnnouncement encodes an announcement message. It may return multiple messages if the input does not fit into one. findPeer is a list of node IDs (blake3 hash of peer ID compressed form) findValue is a list of hashes files is a list of files stored to inform about

func EncodeGetBlock

func EncodeGetBlock(senderPrivateKey *btcec.PrivateKey, data []byte, control uint8, blockchainPublicKey *btcec.PublicKey, limitBlockCount, maxBlockSize uint64, targetBlocks []BlockRange, transferID uuid.UUID) (packetRaw []byte, err error)

EncodeGetBlock encodes a Get Block message. The embedded packet size must be smaller than TransferMaxEmbedSize.

func EncodeResponse

func EncodeResponse(sendUA bool, hash2Peers []Hash2Peer, filesEmbed []EmbeddedFileData, hashesNotFound [][]byte, features byte, blockchainHeight, blockchainVersion uint64, userAgent string) (packetsRaw [][]byte, err error)

EncodeResponse encodes a response message hash2Peers will be modified.

func EncodeTransfer

func EncodeTransfer(senderPrivateKey *btcec.PrivateKey, data []byte, control, transferProtocol uint8, hash []byte, offset, limit uint64, transferID uuid.UUID) (packetRaw []byte, err error)

EncodeTransfer encodes a transfer message. The embedded packet size must be smaller than TransferMaxEmbedSize.

func EncodeTraverse

func EncodeTraverse(senderPrivateKey *btcec.PrivateKey, embeddedPacketRaw []byte, receiverEnd *btcec.PublicKey, relayPeer *btcec.PublicKey) (packetRaw []byte, err error)

EncodeTraverse encodes a traverse message

func EncodeTraverseSetAddress

func EncodeTraverseSetAddress(raw []byte, IPv4 net.IP, PortIPv4, PortIPv4ReportedExternal uint16, IPv6 net.IP, PortIPv6, PortIPv6ReportedExternal uint16) (err error)

EncodeTraverseSetAddress sets the IP and Port in a traverse message that shall be forwarded to another peer

func FileTransferReadHeader

func FileTransferReadHeader(reader io.Reader) (fileSize, transferSize uint64, err error)

FileTransferReadHeader starts reading the header for a file transfer. It will only read the header and keeps the connection open.

func FileTransferWriteHeader

func FileTransferWriteHeader(writer io.Writer, fileSize, transferSize uint64) (err error)

FileTransferWriteHeader starts writing the header for a file transfer.

func HashData

func HashData(data []byte) (hash []byte)

HashData abstracts the hash function.

func PacketEncrypt

func PacketEncrypt(senderPrivateKey *btcec.PrivateKey, receiverPublicKey *btcec.PublicKey, packet *PacketRaw) (raw []byte, err error)

PacketEncrypt encrypts a packet using the provided senders private key and receivers compressed public key.

func PacketLiteEncode

func PacketLiteEncode(id uuid.UUID, data []byte) (raw []byte, err error)

Encodes a lite packet.

func PublicKey2NodeID

func PublicKey2NodeID(publicKey *btcec.PublicKey) (nodeID []byte)

PublicKey2NodeID translates the Public Key into the node ID used in the Kademlia network. It is also referenced in various other places including blockchain data at runtime. The node ID identifies the owner.

Types

type BlockRange

type BlockRange struct {
	Offset uint64 // Block number start
	Limit  uint64 // Count of blocks
}

BlockRange is a single start-count range.

func BlockTransferReadBlock

func BlockTransferReadBlock(reader io.Reader, maxBlockSize uint64) (data []byte, targetBlock BlockRange, blockSize uint64, availability uint8, err error)

BlockTransferReadBlock reads the header and the block from the reader

type EmbeddedFileData

type EmbeddedFileData struct {
	ID   KeyHash // Hash of the file
	Data []byte  // Data
}

EmbeddedFileData contains embedded data sent within a response

type Hash2Peer

type Hash2Peer struct {
	ID      KeyHash      // Hash that was queried
	Closest []PeerRecord // Closest peers
	Storing []PeerRecord // Peers known to store the data identified by the hash
	IsLast  bool         // Whether it is the last records returned for the requested hash and no more results will follow
}

Hash2Peer links a hash to peers who are known to store the data and to peers who are considered close to the hash

type InfoStore

type InfoStore struct {
	ID   KeyHash // Hash of the file
	Size uint64  // Size of the file
	Type uint8   // Type of the file: 0 = File, 1 = Header file containing list of parts
}

InfoStore informs about files stored

type KeyHash

type KeyHash struct {
	Hash []byte
}

KeyHash is a single blake3 key hash

type LiteID

type LiteID struct {
	ID uuid.UUID // ID

	Data interface{} // Optional high-level data associated with the ID
	// contains filtered or unexported fields
}

LiteID contains session information for a bidirectional transfer of data

type LiteRouter

type LiteRouter struct {
	sync.Mutex // synchronized access to the IDs
	// contains filtered or unexported fields
}

LiteRouter keeps track of accepted (expected) packet IDs.

func NewLiteRouter

func NewLiteRouter() (router *LiteRouter)

Creates a new manager to keep track of accepted IDs.

func (*LiteRouter) All

func (router *LiteRouter) All() (sessions []*LiteID)

Returns all lite sessions

func (*LiteRouter) IsPacketLite

func (router *LiteRouter) IsPacketLite(raw []byte) (isLite bool, err error)

IsPacketLite identifies a lite packet based on its ID. If the ID is not recognized, it fails.

func (*LiteRouter) LookupLiteID

func (router *LiteRouter) LookupLiteID(id uuid.UUID) (info *LiteID)

func (*LiteRouter) NewLiteID

func (router *LiteRouter) NewLiteID(data interface{}, timeout time.Duration, invalidateFunc func()) (info *LiteID)

Returns a new lite ID to be used.

func (*LiteRouter) PacketLiteDecode

func (router *LiteRouter) PacketLiteDecode(raw []byte) (packet *PacketLiteRaw, err error)

PacketLiteDecode a lite packet. It will identify the lite packet based on its ID. If the ID is not recognized (which is the case for regular Peernet packets), the function fails. It does not perform any decryption.

func (*LiteRouter) RegisterLiteID

func (router *LiteRouter) RegisterLiteID(id uuid.UUID, data interface{}, timeout time.Duration, invalidateFunc func()) (info *LiteID)

type MessageAnnouncement

type MessageAnnouncement struct {
	*MessageRaw                   // Underlying raw message
	Protocol          uint8       // Protocol version supported (low 4 bits).
	Features          uint8       // Feature support
	Actions           uint8       // Action bit array. See ActionX
	BlockchainHeight  uint64      // Blockchain height
	BlockchainVersion uint64      // Blockchain version
	PortInternal      uint16      // Internal port. Can be used to detect NATs.
	PortExternal      uint16      // External port if known. 0 if not. Can be used for UPnP support.
	UserAgent         string      // User Agent. Format "Software/Version". Required in the initial announcement/bootstrap. UTF-8 encoded. Max length is 255 bytes.
	FindPeerKeys      []KeyHash   // FIND_PEER data
	FindDataKeys      []KeyHash   // FIND_VALUE data
	InfoStoreFiles    []InfoStore // INFO_STORE data
}

MessageAnnouncement is the decoded announcement message.

func DecodeAnnouncement

func DecodeAnnouncement(msg *MessageRaw) (result *MessageAnnouncement, err error)

DecodeAnnouncement decodes the incoming announcement message. Returns nil if invalid.

type MessageGetBlock

type MessageGetBlock struct {
	*MessageRaw                          // Underlying raw message.
	Control             uint8            // Control. See TransferControlX.
	BlockchainPublicKey *btcec.PublicKey // Peer ID of blockchain to transfer.

	// fields valid only for GetBlockControlRequestStart
	TransferID      uuid.UUID    // Transfer ID to identify lite packets.
	LimitBlockCount uint64       // Limit total count of blocks to transfer
	MaxBlockSize    uint64       // Limit of bytes per block to transfer max. Blocks exceeding this limit will not be transferred.
	TargetBlocks    []BlockRange // Target list of block ranges to transfer.

	// fields valid only for GetBlockControlActive
	Data []byte // Embedded protocol data.
}

MessageGetBlock is the decoded Get Block message.

func DecodeGetBlock

func DecodeGetBlock(msg *MessageRaw) (result *MessageGetBlock, err error)

DecodeGetBlock decodes a Get Block message

func (*MessageGetBlock) IsLast

func (msg *MessageGetBlock) IsLast() bool

IsLast checks if the incoming message is the last one in this transfer.

type MessageRaw

type MessageRaw struct {
	PacketRaw
	SenderPublicKey *btcec.PublicKey // Sender Public Key, ECDSA (secp256k1) 257-bit
	SequenceInfo    *SequenceExpiry  // Sequence
}

MessageRaw is a high-level message between peers that has not been decoded

type MessageResponse

type MessageResponse struct {
	*MessageRaw                          // Underlying raw message
	Protocol          uint8              // Protocol version supported (low 4 bits).
	Features          uint8              // Feature support (high 4 bits). Future use.
	Actions           uint8              // Action bit array. See ActionX
	BlockchainHeight  uint64             // Blockchain height
	BlockchainVersion uint64             // Blockchain version
	PortInternal      uint16             // Internal port. Can be used to detect NATs.
	PortExternal      uint16             // External port if known. 0 if not. Can be used for UPnP support.
	UserAgent         string             // User Agent. Format "Software/Version". Required in the initial announcement/bootstrap. UTF-8 encoded. Max length is 255 bytes.
	Hash2Peers        []Hash2Peer        // List of peers that know the requested hashes or at least are close to it
	FilesEmbed        []EmbeddedFileData // Files that were embedded in the response
	HashesNotFound    [][]byte           // Hashes that were reported back as not found
}

MessageResponse is the decoded response message.

func DecodeResponse

func DecodeResponse(msg *MessageRaw) (result *MessageResponse, err error)

DecodeResponse decodes the incoming response message. Returns nil if invalid.

func (*MessageResponse) IsLast

func (msg *MessageResponse) IsLast() bool

IsLast checks if the incoming message is the last expected response in this sequence.

type MessageTransfer

type MessageTransfer struct {
	*MessageRaw                // Underlying raw message.
	Control          uint8     // Control. See TransferControlX.
	TransferProtocol uint8     // Embedded transfer protocol: 0 = UDT
	Hash             []byte    // Hash of the file to transfer.
	Offset           uint64    // Offset to start reading at. Only TransferControlRequestStart.
	Limit            uint64    // Limit (count of bytes) to read starting at the offset. Only TransferControlRequestStart.
	TransferID       uuid.UUID // Transfer ID to identify lite packets.
	Data             []byte    // Embedded protocol data. Only TransferControlActive.
}

MessageTransfer is the decoded transfer message. It is sent to initiate a file transfer, and to send data as part of a file transfer. The actual file data is encapsulated via UDT.

func DecodeTransfer

func DecodeTransfer(msg *MessageRaw) (result *MessageTransfer, err error)

DecodeTransfer decodes a transfer message

func (*MessageTransfer) IsLast

func (msg *MessageTransfer) IsLast() bool

IsLast checks if the incoming message is the last one in this transfer.

type MessageTraverse

type MessageTraverse struct {
	*MessageRaw                               // Underlying raw message.
	TargetPeer               *btcec.PublicKey // End receiver peer ID.
	AuthorizedRelayPeer      *btcec.PublicKey // Peer ID that is authorized to relay this message to the end receiver.
	Expires                  time.Time        // Expiration time when this forwarded message becomes invalid.
	EmbeddedPacketRaw        []byte           // Embedded packet.
	SignerPublicKey          *btcec.PublicKey // Public key that signed this message, ECDSA (secp256k1) 257-bit
	IPv4                     net.IP           // IPv4 address of the original sender. Set by authorized relay. 0 if not set.
	PortIPv4                 uint16           // Port (actual one used for connection) of the original sender. Set by authorized relay.
	PortIPv4ReportedExternal uint16           // External port as reported by the original sender. This is used in case of port forwarding (manual or automated).
	IPv6                     net.IP           // IPv6 address of the original sender. Set by authorized relay. 0 if not set.
	PortIPv6                 uint16           // Port (actual one used for connection) of the original sender. Set by authorized relay.
	PortIPv6ReportedExternal uint16           // External port as reported by the original sender. This is used in case of port forwarding (manual or automated).
}

MessageTraverse is the decoded traverse message. It is sent by an original sender to a relay, to a final receiver (targert peer).

func DecodeTraverse

func DecodeTraverse(msg *MessageRaw) (result *MessageTraverse, err error)

DecodeTraverse decodes a traverse message. It does not verify if the receiver is authorized to read or forward this message. It validates the signature, but does not validate the signer.

type PacketLiteRaw

type PacketLiteRaw struct {
	ID      uuid.UUID // ID
	Payload []byte    // Payload
	Session *LiteID   // Session info
}

PacketLiteRaw is a decrypted P2P lite packet

type PacketRaw

type PacketRaw struct {
	Protocol uint8  // Protocol version = 0
	Command  uint8  // 0 = Announcement
	Sequence uint32 // Sequence number
	Payload  []byte // Payload
}

PacketRaw is a decrypted P2P message

func PacketDecrypt

func PacketDecrypt(raw []byte, receiverPublicKey *btcec.PublicKey) (packet *PacketRaw, senderPublicKey *btcec.PublicKey, err error)

PacketDecrypt decrypts the packet, verifies its signature and returns a high-level version of the packet.

func (*PacketRaw) SetSelfReportedPorts

func (packet *PacketRaw) SetSelfReportedPorts(portI, portE uint16)

SetSelfReportedPorts sets the fields Internal Port and External Port according to the connection details. This is important for the remote peer to make smart decisions whether this peer is behind a NAT/firewall and supports port forwarding/UPnP.

type PeerRecord

type PeerRecord struct {
	PublicKey                *btcec.PublicKey // Public Key
	NodeID                   []byte           // Kademlia Node ID
	IPv4                     net.IP           // IPv4 address. 0 if not set.
	IPv4Port                 uint16           // Port (actual one used for connection)
	IPv4PortReportedInternal uint16           // Internal port as reported by that peer. This can be used to identify whether the peer is potentially behind a NAT.
	IPv4PortReportedExternal uint16           // External port as reported by that peer. This is used in case of port forwarding (manual or automated).
	IPv6                     net.IP           // IPv6 address. 0 if not set.
	IPv6Port                 uint16           // Port (actual one used for connection)
	IPv6PortReportedInternal uint16           // Internal port as reported by that peer. This can be used to identify whether the peer is potentially behind a NAT.
	IPv6PortReportedExternal uint16           // External port as reported by that peer. This is used in case of port forwarding (manual or automated).
	LastContact              uint32           // Last contact in seconds
	LastContactT             time.Time        // Last contact time translated from seconds
	Features                 uint8            // Feature support. Same as in Announcement/Response message.
}

PeerRecord informs about a peer

type SequenceExpiry

type SequenceExpiry struct {
	SequenceNumber uint32 // Sequence number

	Data interface{} // Optional high-level data associated with the sequence
	// contains filtered or unexported fields
}

SequenceExpiry contains the decoded sequence information of a message.

type SequenceManager

type SequenceManager struct {
	ReplyTimeout int // The round-trip timeout for message sequences.

	sync.Mutex // synchronized access to the sequences
	// contains filtered or unexported fields
}

SequenceManager stores all message sequence numbers that are valid at the moment

func NewSequenceManager

func NewSequenceManager(ReplyTimeout int) (manager *SequenceManager)

NewSequenceManager creates a new sequence manager. The ReplyTimeout is in seconds. The expiration function is started immediately.

func (*SequenceManager) ArbitrarySequence

func (manager *SequenceManager) ArbitrarySequence(publicKey *btcec.PublicKey, data interface{}) (info *SequenceExpiry)

ArbitrarySequence returns an arbitrary sequence to be used for uncontacted peers

func (*SequenceManager) InvalidateSequence

func (manager *SequenceManager) InvalidateSequence(publicKey *btcec.PublicKey, sequenceNumber uint32, bidirectional bool)

InvalidateSequence invalidates the sequence number. It does not call invalidateFunc.

func (*SequenceManager) NewSequence

func (manager *SequenceManager) NewSequence(publicKey *btcec.PublicKey, messageSequence *uint32, data interface{}) (info *SequenceExpiry)

NewSequence returns a new sequence and registers it. messageSequence must point to the variable holding the continuous next sequence number. Use only for Announcement and Ping messages.

func (*SequenceManager) NewSequenceBi

func (manager *SequenceManager) NewSequenceBi(publicKey *btcec.PublicKey, messageSequence *uint32, data interface{}, timeout time.Duration, invalidateFunc func()) (info *SequenceExpiry)

NewSequenceBi returns a new bidirectional sequence and registers it. messageSequence must point to the variable holding the continuous next sequence number.

func (*SequenceManager) RegisterSequenceBi

func (manager *SequenceManager) RegisterSequenceBi(publicKey *btcec.PublicKey, sequenceNumber uint32, data interface{}, timeout time.Duration, invalidateFunc func()) (info *SequenceExpiry)

RegisterSequenceBi registers a bidirectional sequence initiated by a remote peer. The caller must specify the timeout (which will be reset every time a new message appears in this sequence). This is needed for bidirectional responses to accept subsequent incoming messages from the remote peer.

func (*SequenceManager) ValidateSequence

func (manager *SequenceManager) ValidateSequence(publicKey *btcec.PublicKey, sequenceNumber uint32, invalidate, extendValidity bool) (sequenceInfo *SequenceExpiry, valid bool, rtt time.Duration)

ValidateSequence validates the sequence number of an incoming message. It will set raw.sequence if valid.

func (*SequenceManager) ValidateSequenceBi

func (manager *SequenceManager) ValidateSequenceBi(publicKey *btcec.PublicKey, sequenceNumber uint32, isLast bool) (sequenceInfo *SequenceExpiry, valid bool, rtt time.Duration)

ValidateSequenceBi validates the sequence number of an incoming message. It will set raw.sequence if valid.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL