Als hätten wir keine Blockchain

Wie haben wir mit smart-contract ein System zur Auswahl der besten technologischen Projekte in IT MTS aufgebaut? Und in welche „Fallen“ sind wir geraten, konnten aber raus und haben am Ende bewiesen, dass es möglich ist, eine verteilte Registrierung auf Mobilgeräten zu führen!



Warum wurde ein Blockchain-basiertes System benötigt?


Beginnen wir von vorne. MTS hat eine lange Tradition - das beste Technologieprojekt eines Jahres auszuwählen und sein Team zu belohnen. Das Team erhält Preise, Respekt und Ruhm. Im Laufe der Jahre sind verschiedene Projekte zu Gewinnern geworden: von hoch ausgelasteten Telekommunikationssystemen bis hin zu Systemen mit künstlicher Intelligenz.

Die Auswahl des besten Projekts erfolgte immer in mehreren Schritten:

  • Teams bewerben sich
  • Die Abstimmung mit angesehenen technischen Experten findet statt
  • Nach Experten werden Projekte von Managern ausgewählt
  • Nach Abschluss aller Phasen wählt der Big Boss das beste Projekt aus.

Wir haben entschieden, dass dieses Schema für die Teilnehmer nicht transparent genug ist, und haben uns überlegt: Warum nicht absolut allen Experten des Unternehmens die Möglichkeit geben, das beste technologische Projekt auszuwählen? 


Wenn wir diese Gelegenheit direkt am Telefon umsetzen, sehen wir die aktuelle Bewertung der Projekte und wer für wen stimmt - dies gewährleistet vollständige Transparenz des Prozesses.

Wir lesen mehrere Artikel über Blockchain und die Idee, ein verteiltes Registrierungssystem aufzubauen, das fest in unseren Köpfen verankert ist. Was aber, wenn wir hier Smart-Contract anwenden ?

Folgende Eigenschaften haben uns angezogen:

  • Offenheit - Es gibt keinen einzigen Server, auf dem Sie Informationen bearbeiten können.
  • Informationen, die in einer verteilten Registrierung gespeichert sind, bleiben für immer dort.
  • Informationen können nicht gefälscht werden (na ja ... praktisch)

Keine Blockchain




Blockchain selbst sollte für solche Wahlen nicht verwendet werden. Was aber, wenn wir die Protokolle zur Konsensbildung in verteilten Systemen auf die Konsensbildung in den menschlichen Beziehungen anwenden?

Da wir in einem offenen Netzwerk arbeiten müssen, müssen wir uns vor nicht-byzantinischen Angriffen und vor dem Ersetzen von Informationen auf den Geräten der Benutzer schützen .

Was sind die Alternativen


Das bekannteste Protokoll ist PAXOS. Es fehlt ein expliziter Anführer, und alle Änderungen werden in zwei Phasen festgeschrieben. Zu Beginn jeder Änderung tritt Propose auf. Wenn es erfolgreich war, wird Akzeptieren gesendet.


Ein Merkmal des Algorithmus kann als die Tatsache bezeichnet werden, dass er globale Zeitgeber verwendet, um zu bestimmen, welche Anforderung früher generiert wurde, und dass der Knoten, der Änderungen vornimmt, mit allen Knoten des Netzwerks kommunizieren sollte. Lesen Sie mehr über den Algorithmus hier .

Der Algorithmus wird an vielen Stellen verwendet, beispielsweise im Cassandra DBMS. Dieses Protokoll hat uns im Hinblick auf die Komplexität seiner Implementierung für die Aufgabe nicht gefallen. Aber die zweite Option kam auf uns zu - es ist RAFT. In der Tat ist dies eine Weiterentwicklung des PAXOS-Protokolls mit einem klaren Führer.

Das vereinfachte Protokoll kann wie folgt beschrieben werden:
· Es wird ein Netzwerk von Geräten aufgebaut, die sich gegenseitig kennen.
· Geräte wählen unter sich einen Leiter aus, der „wichtige Entscheidungen“ trifft (z. B. Hinzufügen eines Eintrags zur Registrierung oder Ändern der Zusammensetzung des Netzwerks).
· Das Leader-Gerät ist für die Verteilung von Informationen im gesamten Netzwerk verantwortlich, sodass diese überall identisch sind.
· Sobald der Anführer seine Pflichten nicht mehr erfüllt, wählen Sie einen neuen Anführer.

Lesen Sie über das Protokoll hier .

Unsere Umsetzung


Was machen wir und warum ist die Welt ein anderes Fahrrad? 


Fast alle Benutzer unserer Registrierung verfügen über mobile Geräte, die fast immer eingeschaltet und fast immer online sind, und verwenden sie tatsächlich fast immer. Daher haben wir beschlossen, den Verteilungsregistrierungsalgorithmus auf mobilen Geräten und nicht auf der Serverinfrastruktur wie bei anderen bekannten Implementierungen auszuführen .

Mal sehen, in welche "Fallen" wir geraten sind, aber wir haben es geschafft, rauszukommen ...

Falle Nummer 1: „Meine Adresse ist nicht zu Hause und nicht auf der Straße“


"Plötzlich" stellte sich heraus, dass jedes Gerät miteinander kommunizieren kann, um ein P2P-Netzwerk aufzubauen, das eine verteilte Registrierung unter Verwendung des RAFT-Protokolls für die Datenreplikation implementiert. Dies bedeutet, dass es sowohl ein Client als auch ein Server ist. Daher benötigen wir für jedes Mobiltelefon eine öffentliche „weiße“ IP-Adresse (möglicherweise nicht).

Die Anzahl der echten IPv4s ist sehr begrenzt. Daher verwenden Telekommunikationsbetreiber die NAT-Technologie (Network Address Translation) im PAT-Modus (Port Address Translation) und übersetzen mehrere IP-Adressen des internen Netzwerks (die an Teilnehmer verteilt werden) in eine externe öffentliche IP-Adresse. Daher ist die Möglichkeit, eingehende Verbindungen aus dem Internet zu akzeptieren, ausgeschlossen.

Die gute Nachricht ist, dass es viel IPv6 gibt! 


Das Basispaket enthält IPv6-Unterstützung. Außerdem unterstützen alle modernen Telefone IPv6, und der Betreiber weist dem Teilnehmer eine öffentliche „weiße“ v6-Adresse zu. Wir wählen IPv6.

Falle Nummer 2: Alle gingen schlafen


Im Gegensatz zu Servern werden Mobiltelefone manchmal immer noch ausgeschaltet. Wir haben dies beim Testen des ersten Prototyps festgestellt. Darüber hinaus ist die vom Betreiber bereitgestellte IPv6-Adresse öffentlich, jedoch nicht statisch. Jede neue Kommunikationssitzung ist eine neue Adresse. Die Adresse des Mobilgeräts kann sich jederzeit ändern. Und wenn es im Netzwerk kein einziges Telefon mit der uns bekannten Adresse gibt, existiert es einfach nicht mehr (es gibt nichts, mit dem eine Verbindung hergestellt werden kann, um es zu „erhöhen“). Daher mussten wir in gewissem Maße gegen unsere Regel „Kein Server“ verstoßen. Wir haben einen speziellen Knoten in der Cloud mit einer statischen bekannten Adresse erstellt. Seine Aufgabe ist es, die Zusammensetzung des Netzwerks zu speichern / zu aktualisieren und nicht auszuschalten. Das heißt, es ist eine gewöhnliche Site, niemand stimmt nur ab, und wenn Sie sich an sie wenden, können Sie immer die aktuelle Adressliste aller Netzwerkteilnehmer abrufen.

3: 



Es war notwendig, das Problem irgendwie zu lösen, damit nicht jeder für Projekte stimmen konnte, sondern diejenigen, die es brauchten. Die erste Idee war folgende: Führen Sie eine Datenbank mit Telefonnummern von Experten. Sie lehnten dies jedoch ab, da sie der Anwendung nicht das Recht einräumen wollten, auf diese Informationen zuzugreifen.
Infolgedessen machten sie alles einfach: Sie beschlossen, jede Stimme, jeden Registrierungseintrag mit einer digitalen Signatur auf modischen elliptischen Kurven zu versehen, die die Authentizität der Aufzeichnung bestimmen. Im Unternehmensnetzwerk wurde ein WEB-Dienst eingerichtet, der durch Domain-Autorisierung den Experten bestimmte und mit den öffentlichen und privaten Verschlüsselungsschlüsseln (natürlich auf Client-Seite) einen eindeutigen QR-Code für ihn generierte. Der Experte hat den Code aus der Anwendung gescannt und eine Verbindung hergestellt. Danach wurde die aktuelle Version der Registrierung auf seinem Telefon „aufgerollt“ und die Möglichkeit zur Abstimmung wurde angezeigt.

4: Android 
 



Während des Tests stellte sich fast „plötzlich“ heraus, dass einige Benutzer Eigentümer bekannter Modelle mobiler Geräte sind, auf denen das iOS-Betriebssystem ausgeführt wird. Und es wurde klar, dass unsere Registrierungssoftware auf verschiedenen Plattformen ausgeführt werden sollte. Wir haben uns die Programmiersprache Kotlin angesehen, die nicht nur „trendy, stylisch, jugendlich“, sondern auch plattformübergreifend ist .

Das Konzept der Multi-Plattform in Kotlin impliziert, dass es einen Teil des gemeinsamen und plattformspezifischen Codes gibt. Da jedoch die Ressourcen unseres Teams begrenzt sind, haben wir uns die abscheuliche Aufgabe gestellt, eine einzige Version des Quellcodes für alle Plattformen zu verwenden! Natürlich muss das ausführbare Modul für jede Plattform nativ sein. Kotlin war dazu in der Lage.

Gesagt, getan! Wir haben ein einziges SourceSet mit Quellcode, aus dem wir Binärdateien für alle Plattformen (!) Sammeln . Verwenden Sie dazu die Funktion "abhängig" . Cool? Sehr cool!

Falle Nummer 5: Mobiler Verkehr ist nicht kostenlos 



Wie können wir die Interaktion zwischen Netzwerkknoten am effektivsten implementieren, um nicht den gesamten Datenverkehr des Teilnehmers zu verbrauchen und den Akku des Mobilgeräts nicht zu entladen? Wir gehen davon aus, dass das Netzwerk aus 1000 oder mehr Geräten bestehen kann! Die naheliegendste Option ist die Verwendung von UDP anstelle von TCP, z. B. bei der Auswahl des Leiters oder beim Senden von Heartbeats ohne Daten. UDP ist wirtschaftlicher, da es ein einfaches Datenübertragungsmodell ohne „Handshakes“ und Bestätigungen verwendet. Fein! Was sonst? Natürlich asynchrone E / A!

Wir haben die Dokumentation für Kotlin Native sorgfältig gelesen.

Für alle Unix- oder Windows-basierten Ziele (einschließlich Android und iPhone) bieten wir die posix-Plattform lib an. Es enthält Bindungen zur Implementierung des POSIX-Standards durch die Plattform.

Dann lesen wir auch die POSIX-Standarddokumentation sorgfältig durch und finden eine erstaunliche Funktion , mit der wir Socket-Ereignisse im nicht blockierenden Modus verarbeiten können! Nachdem wir uns kopfüber in die wunderbare Welt von Coroutine, Sockets und C Interop gestürzt hatten, konnten wir einen sehr effizienten Transport realisieren. Super!

Und in welcher Form sollen Daten gesendet werden? 



Natürlich CBOR!

Ein kompaktes binäres Datenformat, das zum Glück in der plattformübergreifenden Bibliothek kotlinx.serialization implementiert ist . Einfach super!

Falle Nummer 6: Serialisierung 



Dieses Mal stellte sich wirklich unerwartet heraus, dass kotlinx.serialization nicht unter androidNative steht (unter androidJvm gibt es das natürlich). Sehr geehrte Kollegen von JetBrains haben bestätigt, dass sie derzeit keine Bibliothek für androidNative erstellen. Vor der Veröffentlichung von Kotlin 1.4 ist in der Roadmap kein Platz mehr für diese Aufgabe. 


Was ist zu tun? Wenn der Berg nicht zu Mohammed geht, geht Mohammed zum Berg!

Wir selbst haben kotlinx.serialization für alle Plattformen zusammengestellt, einschließlich androidNative! Das Erstaunlichste ist, dass es funktioniert hat! 


Falle Nummer 7: Wo soll das Protokoll aufbewahrt werden? 



Natürlich im eingebetteten Schlüsselwertspeicher, aber in welchem? Wir haben lmdbx wegen der Kompaktheit des Codes, der Geschwindigkeit, der Multi-Plattform und des Fehlens einer WAL-Datei ausgewählt. Diese Bibliothek wurde von den Jungs von Positive Techlologies entwickelt und stammt aus der legendären LMDB- Bibliothek eines der Autoren von OpenLDAP Howard Chu. Und das wiederum wurzelt in der Implementierung des B + -Baums von Martin Hedenfalk. Die Bibliothek wurde übrigens nicht für androidNative erstellt. Wir haben alle Fehler sorgfältig gesammelt und die Autoren haben umgehend Korrekturen bereitgestellt - wofür wir uns ganz besonders bedanken!

Falle Nummer 8: C Interop 



Alles zusammenzustellen erwies sich als eine nicht triviale Aufgabe. Zusätzlich zu lmdbx- und posix-Sockets haben wir Bibliotheken integriert, um digitale Signaturen auf elliptischen Kurven zu generieren / zu validieren und SHA256 mithilfe des erstaunlichen C-Interop- Mechanismus zu berechnen . In einfachen Worten - von einer nativen Anwendung auf Kotlin aus können Sie die C-Bibliotheksfunktion aufrufen, auch wenn Zeiger auf Zeiger und andere Magie vorhanden sind, sieht alles etwas seltsam aus.

Rufen Sie beispielsweise getaddrinfo auf, um sockaddr zu erhalten.



Wie gefällt dir Ilon Mask?

Das Verknüpfen der C-Bibliothek mit der ausführbaren Datei von Kotlin Native ist eine separate Aufgabe, die wir ebenfalls überstanden haben, jedoch nicht ohne Krücken. Wir bilden die def-Datei dynamisch direkt im Build-Skript, um den korrekten Pfad zu den Bibliotheken relativ zum Projektstammverzeichnis anzugeben, und ersetzen dann den Deskriptor (def-Datei) im Abschnitt cinterops. In der def-Datei selbst wird nur der absolute Pfad bestimmt, der nicht nur ein anderes Format haben kann, wenn die Assembly unter einem anderen Betriebssystem ausgeführt wird, sondern tatsächlich auch auf den lokalen Computern der Entwickler unterschiedlich sein kann, was offensichtlich zu einem Fehler während der Verknüpfung führt.

Über die Wahl


Die Hauptwahlen, die wir tagsüber abgehalten haben. Etwas mehr als 20 Experten haben an Tests mit unserem Netzwerk teilgenommen. 21 Projekte wurden in 5 Kategorien bewertet, dh mehr als 100 Einträge mit Stimmen für Projekte wurden in das Register aufgenommen.

Fazit


Als Ergebnis dieses kleinen Forschungsprojekts konnten wir nachweisen, dass die Verwaltung einer verteilten Registrierung auf Mobilgeräten möglich ist! Dies eröffnet viele Möglichkeiten für die Verwendung dieser Technologie auf IoT-Geräten zur Organisation von Edge-Computing-Computern. Vor uns warten noch Lasttests, Anfälligkeit für Angriffe und Fehlertoleranz. Aber wir glauben, dass wir Erfolg haben werden!

Autoren des Artikels: Architekten und Entwickler des Forschungs- und Entwicklungszentrums von MTS Dmitry Dzyuba, Alexey Vasilenko und Semen Nevrev

All Articles