====== std.blockchain.p2p — Blockchain P2P-Netzwerk ====== ''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. → [[lyx_-_programmiersprache:units:blockchain|std.blockchain (Kern)]] · [[lyx_-_programmiersprache:units|Standard Library]] ---- ===== Protokoll ===== 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 | ---- ===== Node-Struktur (40 Bytes) ===== ^ 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) ---- ===== Öffentliche API ===== ==== Node-Lebenszyklus ==== ^ 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) | ==== Verbindungen ==== ^ 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. ==== Nachrichtenverarbeitung ==== ^ 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: * **QUERY_LATEST** → antwortet mit aktuellem letzten Block * **BROADCAST_TX** → deserialisiert TX und versucht ''BLAddTransaction''; bei Erfolg wird TX vom bc übernommen; bei Ablehnung wird TX freigegeben * **BROADCAST_BLOCK** → siehe Block-Empfang unten ==== Block-Empfang (BROADCAST_BLOCK) ==== ^ 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 | ---- ===== Deserializer ===== 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. ---- ===== IP-Adresse übergeben ===== ''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); ---- ===== Vollständiges Beispiel ===== 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änkungen ===== ^ 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