std.blockchain.p2p implementiert eine TCP-basierte P2P-Kommunikationsschicht für Blockchain-Knoten. Jeder Knoten kann bis zu 32 Peers verbinden, Transaktionen und Blöcke broadcasten und eingehende Verbindungen akzeptieren.
→ std.blockchain (Kern) · Standard Library
Binäres Nachrichtenformat: [1 Byte Typ][4 Bytes Länge BE][N Bytes Payload]
| Konstante | Wert | Richtung | Bedeutung |
|---|---|---|---|
BLP2P_MSG_QUERY_LATEST | 1 | → Peer | Letzten Block anfordern |
BLP2P_MSG_RESP_LATEST | 2 | ← Peer | Antwort mit letztem Block |
BLP2P_MSG_QUERY_CHAIN | 3 | → Peer | Vollständige Kette anfordern (ab Index) |
BLP2P_MSG_RESP_CHAIN | 4 | ← Peer | Ketten-Antwort (definiert, nicht implementiert) |
BLP2P_MSG_BROADCAST_TX | 5 | ↔ beide | Neue Transaktion verteilen |
BLP2P_MSG_BROADCAST_BLOCK | 6 | ↔ beide | Neuen Block verteilen |
Wichtig: QUERY_CHAIN (3) wird gesendet wenn die eigene Kette kürzer ist, aber BLP2PHandleIncoming behandelt weder QUERY_CHAIN noch RESP_CHAIN. Chain-Synchronisation ist daher noch nicht vollständig implementiert.
Weitere Konstanten:
| Konstante | Wert | Bedeutung |
|---|---|---|
BLP2P_MAX_PEERS | 32 | Maximale gleichzeitige Peer-Verbindungen |
BLP2P_MSG_HDR_LEN | 5 | Header-Größe: 1 Typ + 4 Länge |
| Offset | Feld | Beschreibung |
|---|---|---|
| 0 | bc | Zeiger auf die zugehörige Blockchain (aus std.blockchain) |
| 8 | listenPort | TCP-Port zum Lauschen |
| 16 | serverFd | Server-Socket-Deskriptor; -1 wenn nicht gestartet |
| 24 | peerCount | Anzahl aktiver Peer-Verbindungen |
| 32 | peerFds | Zeiger auf Array mit 32 × int64 Socket-FDs (-1 = freier Slot) |
Offset-Konstanten: BLP2P_NODE_BC (0), BLP2P_NODE_PORT (8), BLP2P_NODE_SERVER_FD (16), BLP2P_NODE_PEER_COUNT (24), BLP2P_NODE_PEER_FDS (32), BLP2P_NODE_SIZE (40)
| Funktion | Rückgabe | Beschreibung |
|---|---|---|
BLP2PNodeNew(bc, port) | int64 Node-Ptr | Erstellt P2P-Knoten; alle Peer-Slots auf -1 initialisiert |
BLP2PNodeFree(node) | void | Schließt alle Verbindungen und gibt Node frei |
BLP2PNodeStart(node) | int64 1/0 | Bindet Socket, startet Lauschen; setzt SO_REUSEADDR; 1 = OK |
BLP2PNodeStop(node) | void | Schließt Server-Socket (Peer-Verbindungen bleiben offen) |
| Funktion | Rückgabe | Beschreibung |
|---|---|---|
BLP2PConnectPeer(node, ip, port) | int64 1/0 | Verbindet zu Peer; ip als int64 (4 Bytes big-endian); sendet sofort QUERY_LATEST; 0 wenn kein freier Slot |
BLP2PPoll(node) | int64 1/0 | Akzeptiert eine neue eingehende Verbindung; sendet RESP_LATEST an neuen Peer |
Achtung: BLP2PPoll verwendet blockierendes accept trotz des Namens. Es wartet auf eine neue Verbindung und kehrt nicht sofort zurück wenn keine anliegt. Für nicht-blockierende Nutzung muss der Server-FD vorab auf non-blocking gesetzt werden.
| Funktion | Rückgabe | Beschreibung |
|---|---|---|
BLP2PHandleIncoming(node, fd) | int64 1/0 | Liest und verarbeitet eine Nachricht vom angegebenen FD; 0 = Verbindung getrennt |
BLP2PBroadcastTx(node, tx) | void | Serialisiert TX und sendet ihn an alle Peers |
BLP2PBroadcastBlock(node, block) | void | Serialisiert Block und sendet ihn an alle Peers |
BLP2PHandleIncoming behandelt:
BLAddTransaction; bei Erfolg wird TX vom bc übernommen; bei Ablehnung wird TX freigegeben| Situation | Aktion |
|---|---|
index == lastIdx + 1 und Hash + PoW gültig | Block an Kette anhängen, Ledger aktualisieren, Block rebroadcasten |
index > lastIdx + 1 (eigene Kette kürzer) | QUERY_CHAIN senden (Antwort wird nicht verarbeitet — bekannte Einschränkung) |
index ≤ lastIdx | Block verwerfen |
Die Deserializer-Funktionen werden intern von BLP2PHandleIncoming genutzt, sind aber auch öffentlich für eigene Protokoll-Erweiterungen.
| Funktion | Rückgabe | Beschreibung |
|---|---|---|
BLDeserializeInt32(buf, off) | int64 | Liest 4-Byte big-endian ab Offset off |
BLDeserializeInt64(buf, off) | int64 | Liest 8-Byte big-endian ab Offset off |
BLDeserializeTx(buf, off, outPtr) | int64 neuer Offset | Deserialisiert TX aus buf ab off; schreibt allokierten TX-Ptr nach outPtr[0]; gibt neuen Offset zurück |
BLDeserializeTx allokiert intern einen neuen TX (224 Bytes). Der Aufrufer muss den TX freigeben wenn er nicht via BLAddTransaction an den Mempool übergeben wird.
BLP2PConnectPeer erwartet die IPv4-Adresse als int64 (4 Bytes, big-endian):
// 192.168.1.100 → (192 << 24) | (168 << 16) | (1 << 8) | 100
var ip: int64 := (192 << 24) | (168 << 16) | (1 << 8) | 100;
BLP2PConnectPeer(node, ip, 9000);
import std.blockchain;
import std.blockchain.p2p;
import std.alloc;
import std.io;
fn main(): int64 {
// Blockchain erstellen
var bc: int64 := BLBlockchainNew(1, 50000000, 10);
// P2P-Knoten auf Port 9000 starten
var node: int64 := BLP2PNodeNew(bc, 9000);
if BLP2PNodeStart(node) == 0 then {
PrintLn("Fehler: Port 9000 belegt"c);
BLP2PNodeFree(node);
BLBlockchainFree(bc);
return 1;
}
PrintLn("P2P-Knoten lauscht auf Port 9000"c);
// Zu einem bekannten Peer verbinden: 192.168.1.50:9000
var peerIp: int64 := (192 << 24) | (168 << 16) | (1 << 8) | 50;
if BLP2PConnectPeer(node, peerIp, 9000) == 1 then {
PrintLn("Verbunden mit 192.168.1.50"c);
}
// Hauptschleife (vereinfacht — in echtem Code: epoll/select verwenden)
var fds: int64 := peek64(node + BLP2P_NODE_PEER_FDS);
var i: int64 := 0;
while i < BLP2P_MAX_PEERS do {
var fd: int64 := peek64(fds + i * 8);
if fd != (0 - 1) then {
if BLP2PHandleIncoming(node, fd) == 0 then {
// Verbindung getrennt — Slot freigeben
poke64(fds + i * 8, 0 - 1);
}
}
i := i + 1;
}
BLP2PNodeStop(node);
BLP2PNodeFree(node);
BLBlockchainFree(bc);
return 0;
}
| Einschränkung | Details |
|---|---|
Blockierendes accept | BLP2PPoll wartet auf neue Verbindungen — nicht für Event-Loop ohne epoll geeignet |
| Chain-Sync unvollständig | QUERY_CHAIN wird gesendet, RESP_CHAIN nicht verarbeitet — kein vollständiger Catch-up möglich |
| Max. 32 Peers | Feste Obergrenze — kein dynamisches Wachstum |
| Kein Peer-Discovery | Peer-Adressen müssen manuell via BLP2PConnectPeer eingetragen werden |
| Kein Timeout | Hängende Verbindungen blockieren BLP2PHandleIncoming |
| Nur IPv4 | Kein IPv6-Support |
Letzte Aktualisierung: 2026-06-13