Node Discovery Protocol - Second-Earth/setchain GitHub Wiki

Node Search Protocol

The SETNODE node Search protocol implements a Kademlia-like DHT network.

Node ID

Each node has an encrypted ID, which is the public key corresponding to the key defined on the secp256k1 elliptic curve.

Node distance

The ‘distance’ between two node IDs is a bitwise exclusive OR of the public key hash, and the nodes can be sorted and sorted by the node distance. Node distance calculation formula:

-id1 = keccack256(n1)

-id2 = keccack256(n2)

-distance(id1, id2) = log2(id1 ^ id2)

Node list

The node discovery protocol saves the information of its own node and neighbor nodes. The neighbor nodes are stored in a routing table composed of ‘K buckets’. Each node sorts and sorts the neighbor nodes according to the distance from the neighbor node to its own node, and puts the nodes with similar node distances into a set called bucket, and multiple buckets form K buckets. Currently, each bucket contains 16 neighbor nodes. The neighbor nodes in the bucket are sorted by the last active time: the node that communicated last is placed at the head, and the node that communicated first is placed at the end. When a new node N1 is added, it will insert it into the corresponding bucket based on the node distance. If the number of nodes in the bucket is less than 16, N1 can be added directly to the header. If the bucket is full, the end node N2 needs to be sent a ping packet. If you do not receive a reply from N2, remove N2 and insert N1.

K bucket node limit

There are some other restrictions on adding nodes to the K bucket:

-K bucket has 17 buckets. Nodes whose node distance is less than or equal to (256-17) are added to bucket[0]. Afterwards, each time the distance increases by 1, the bucket position also increases by 1. -Each bucket has two node lists: -Active list: the currently used list. The capacity is 16. -Standby list: If a node in the active list fails, it will be taken from the standby list and added to the active list. The capacity is 10. -Each bucket limits the number of nodes in the same network segment to no more than 2, and the network segment is divided into IP/24. -K bucket limits the total number of nodes in the same network segment in all buckets to no more than 10, and the network segment is divided into IP/24. -When adding a node, it will first try to join the active list. If the active list is full, it will be added to the standby list. If the standby list is also full, it will be discarded.

Recursive query

A search will find the k nodes closest to the node.

When searching for a network node with a target ID, it will first find a group of nodes with the closest node distance from the local K bucket, and send a findnode message (including the target ID) to it, and the response is a neighbors message (including the longest distance). A group of nodes close to the target ID). If the node does not respond quickly, remove it. Currently, IDs are randomly generated at regular intervals and findnode is sent to neighboring nodes to discover new nodes.

personal I.D

In order to prevent traffic amplification attacks, it is necessary to verify whether the sender of the query participates in the discovery protocol. The sender needs to send a valid Pong packet within 12 hours.

data pack

The node discovery protocol uses the UDP protocol for communication. The largest packet is limited to 1280 bytes.

Packet consists of packet-header and packet-data fields:

packet = packet-header || packet-data

Each packet starts with the header. packet-header:

packet-header = hash || signature || packet-type
hash = keccak256(signature || packet-type || packet-data)
signature = sign(packet-type || packet-data)

Each packet needs to be signed by the private key corresponding to the node ID. The signature field is encoded as a 65-byte array containing r, s, and v.

The packet-type field is a single byte, which defines the message type. packet-data is the RLP code corresponding to the message type.

Message type

PingPacket(0x01)

packet-data = [version, NetID, from, to, expiration, ...]
version = 5
NetID = cmd.param
from = [sender-ip, sender-udp-port, sender-tcp-port]
to = [recipient-ip, recipient-udp-port, 0]

-Extra data at the end of packet-data will be ignored (can be used for protocol upgrade). -The different version value will also be ignored (can be used to upgrade the protocol). -The NetID field is a configuration field, and messages with different NetIDs will be ignored. -The expiration field is the UNIX timestamp. Expired messages will be ignored.

After receiving the ping packet, you need to reply with a pong packet and add the sender to the node list.

If the sender of the ping packet has not been contacted for more than 12 hours, an additional ping needs to be sent to the sender.

Pong Packet (0x02)

packet-data = [version, NetID, to, ping-hash, expiration, ...]

The Pong packet is used to respond to the Ping packet.

ping-hash is the hash of the corresponding Ping packet. If the hash of the received Pong packet is inconsistent with the Ping packet, it will be ignored.

FindNode Packet (0x03)

packet-data = [version, NetID, target, expiration, ...]

The FindNode package is used to request nodes that are close to the target.

The target field is a 64-byte array that represents the secp256k1 public key.

When FindNode receives it, it needs to reply the Neighbors packet. The Neighbors packet contains up to 16 nodes that are close to the target node.

Neighbors Packet (0x04)

packet-data = [version, NetID, nodes, expiration, ...]
nodes = [[ip, udp-port, tcp-port, node-id], ...]

The Neighbors package is used to respond to the FindNode package.

⚠️ **GitHub.com Fallback** ⚠️