So erstellen Sie eine Node.js-API für die Ethereum-Blockchain
Veröffentlicht: 2022-03-10Die Blockchain-Technologie ist in den letzten zehn Jahren auf dem Vormarsch und hat eine ganze Reihe von Produkten und Plattformen zum Leben erweckt, darunter Chainalysis (Finanztechnologie), Burstiq (Gesundheitstechnologie), Filament (IoT), Opus (Musik-Streaming). und Okular (Cybersicherheit).
Anhand dieser Beispiele können wir sehen, dass Blockchain viele Produkte und Anwendungsfälle durchdringt – was sie sehr wichtig und nützlich macht. In der Fintech (Finanztechnologie) wird es als dezentrales Hauptbuch für Sicherheit und Transparenz an Orten wie Chain, Chainalysis verwendet und ist auch in der Gesundheitstechnologie für die Sicherheit sensibler Gesundheitsdaten in Burstiq und Robomed nützlich – nicht zu vergessen in der Medientechnologie wie Opus und Audius, die ebenfalls Blockchain für Tantiementransparenz verwenden und somit volle Tantiemen erhalten.
Ocular verwendet Sicherheit, die mit Blockchain für das Identitätsmanagement für biometrische Systeme geliefert wird, während Filament Blockchain-Ledger für verschlüsselte Kommunikation in Echtzeit verwendet. Dies zeigt, wie wichtig Blockchain für uns geworden ist, indem sie unser Leben verbessert. Aber was genau ist eine Blockchain?
Eine Blockchain ist eine Datenbank , die über ein Netzwerk von Computern gemeinsam genutzt wird. Sobald ein Datensatz zur Kette hinzugefügt wurde, ist es ziemlich schwierig, ihn zu ändern. Um sicherzustellen, dass alle Kopien der Datenbank gleich sind, führt das Netzwerk ständige Überprüfungen durch.
Warum brauchen wir Blockchain? Blockchain ist eine sichere Möglichkeit, Aktivitäten aufzuzeichnen und Daten auf dem neuesten Stand zu halten, während der Verlauf aufgezeichnet wird, im Vergleich zu herkömmlichen Aufzeichnungen oder Datenbanken, bei denen Hacks, Fehler und Ausfallzeiten sehr wahrscheinlich sind. Die Daten können von niemandem beschädigt oder versehentlich gelöscht werden, und Sie profitieren sowohl von einer historischen Datenspur als auch von einer sofort aktuellen Aufzeichnung, die nicht gelöscht werden kann oder aufgrund von Ausfallzeiten eines Servers unzugänglich wird.
Da die gesamte Blockchain auf vielen Computern dupliziert wird, kann jeder Benutzer die gesamte Blockchain anzeigen. Transaktionen oder Aufzeichnungen werden nicht von einem zentralen Administrator verarbeitet, sondern von einem Netzwerk von Benutzern, die daran arbeiten, die Daten zu überprüfen und einen Konsens zu erzielen.
Anwendungen, die Blockchain verwenden, werden als dApps (Decentralized Applications) bezeichnet. Wenn wir uns heute umschauen, finden wir hauptsächlich dezentrale Apps in Fintech, aber Blockchain geht über dezentrale Finanzen hinaus. Wir haben Gesundheitsplattformen, Musik-Streaming-/Sharing-Plattformen, E-Commerce-Plattformen, Cybersicherheitsplattformen und IOTs, die sich wie oben erwähnt in Richtung dezentraler Anwendungen (dApps) bewegen.
Wann wäre es also sinnvoll, die Verwendung von Blockchain für unsere Anwendungen anstelle einer Standarddatenbank oder eines Datensatzes in Erwägung zu ziehen?
Allgemeine Anwendungen von Blockchain
- Verwaltung und Sicherung digitaler Beziehungen
Überall dort, wo Vermögen langfristig und transparent erfasst werden soll (z. B. zur Erfassung von Grundstücks- oder Wohnungsrechten), könnte die Blockchain die ideale Lösung sein. Insbesondere die „intelligenten Verträge“ von Ethereum eignen sich hervorragend zur Erleichterung digitaler Beziehungen. Mit einem Smart Contract können automatisierte Zahlungen freigegeben werden, wenn die Parteien einer Transaktion zustimmen, dass ihre Bedingungen erfüllt wurden. - Beseitigung von Zwischenhändlern/Gatekeepern
Beispielsweise müssen die meisten Anbieter derzeit mit Gästen über eine zentralisierte Aggregator-Plattform wie Airbnb oder Uber interagieren (die wiederum bei jeder Transaktion einen Anteil einnimmt). Blockchain könnte das alles ändern.
TUI beispielsweise ist von der Leistungsfähigkeit der Blockchain so überzeugt, dass sie wegweisend ist, um Hoteliers und Kunden direkt miteinander zu verbinden. Auf diese Weise können sie auf einfache, sichere und konsistente Weise über Blockchain abwickeln, anstatt über eine zentrale Buchungsplattform. - Zeichnen Sie sichere Transaktionen zwischen Partnern auf, um Vertrauen zu gewährleisten
Eine traditionelle Datenbank mag gut sein, um einfache Transaktionen zwischen zwei Parteien aufzuzeichnen, aber wenn die Dinge komplizierter werden, kann Blockchain helfen, Engpässe zu reduzieren und Beziehungen zu vereinfachen. Darüber hinaus macht die zusätzliche Sicherheit eines dezentralisierten Systems Blockchain ideal für Transaktionen im Allgemeinen.
Ein Beispiel ist die University of Melbourne, die damit begann, ihre Aufzeichnungen in Blockchain zu speichern. Der vielversprechendste Anwendungsfall für Blockchain in der Hochschulbildung ist die Umgestaltung der „Aufbewahrung“ von Abschlüssen, Zertifikaten und Diplomen. Dies spart eine Menge Kosten von dedizierten Servern für die Speicherung oder Aufzeichnung. - Aufbewahrung von Aufzeichnungen über vergangene Aktionen für Anwendungen, bei denen Daten in ständigem Fluss sind
Blockchain ist eine bessere und sicherere Möglichkeit, die Aktivität aufzuzeichnen und die Daten aktuell zu halten, während gleichzeitig eine Aufzeichnung ihrer Historie geführt wird. Die Daten können von niemandem beschädigt oder versehentlich gelöscht werden, und Sie profitieren sowohl von einer historischen Datenspur als auch von einer sofort aktuellen Aufzeichnung. Ein Beispiel für einen guten Anwendungsfall ist Blockchain im E-Commerce, sowohl Blockchain als auch E-Commerce beinhalten Transaktionen.
Blockchain macht diese Transaktionen sicherer und schneller, während E-Commerce-Aktivitäten darauf angewiesen sind. Die Blockchain-Technologie ermöglicht es Benutzern, digitale Assets sowohl automatisch als auch manuell zu teilen und sicher zu speichern. Diese Technologie ist in der Lage, Benutzeraktivitäten wie Zahlungsabwicklung, Produktsuche, Produktkäufe und Kundenbetreuung abzuwickeln. Es reduziert auch die Ausgaben für die Bestandsverwaltung und die Zahlungsabwicklung. - Dezentralisierung macht es möglich, überall eingesetzt zu werden
Im Gegensatz zu früher, wo wir uns aus verschiedenen Gründen wie Währungsumtauschrichtlinien auf eine bestimmte Region beschränken müssen, erschweren Beschränkungen von Zahlungsgateways den Zugang zu finanziellen Ressourcen vieler Länder, die nicht in Ihrer Region oder Ihrem Kontinent liegen. Mit dem Aufstieg und der Macht der Dezentralisierung oder des Peer-to-Peer-Systems von Blockchain wird es einfacher, mit anderen Ländern zusammenzuarbeiten.
Beispielsweise kann ein E-Commerce-Geschäft in Europa Verbraucher in Afrika haben und benötigt keinen Zwischenhändler, um ihre Zahlungsanforderungen zu bearbeiten. Darüber hinaus öffnen diese Technologien Online-Händlern Türen, um mit Bitcoin, also einer Kryptowährung, die Verbrauchermärkte in fernen Ländern zu nutzen. - Blockhain ist technologieneutral
Blockchain funktioniert mit allen und jedem Technologie-Stack, der von einem Entwickler verwendet wird. Sie müssen Node nicht als Python-Entwickler lernen, um Blockchain zu verwenden oder Golang zu lernen. Dies macht Blockchain sehr einfach zu bedienen.
Wir können es tatsächlich direkt mit unseren Frontend-Apps in Vue/React verwenden, wobei die Blockchain als unsere einzige Datenbank für einfache, unkomplizierte Aufgaben und Anwendungsfälle fungiert, wie das Hochladen von Daten oder das Abrufen von Hashes zum Anzeigen von Aufzeichnungen für unsere Benutzer oder das Erstellen von Frontend-Spielen wie Casino Spiele und Wettspiele (bei denen ein hohes Maß an Vertrauen erforderlich ist). Außerdem können wir mit der Leistungsfähigkeit von web3 Daten direkt in der Kette speichern.
Nun haben wir eine ganze Reihe von Vorteilen der Verwendung von Blockchain gesehen, aber wann sollten wir uns überhaupt nicht die Mühe machen, eine Blockchain zu verwenden?
Nachteile von Blockchain
- Reduzierte Geschwindigkeit für digitale Transaktionen
Blockchains erfordern enorme Mengen an Rechenleistung, was die Geschwindigkeit digitaler Transaktionen tendenziell verringert, obwohl es Problemumgehungen gibt, ist es ratsam, zentralisierte Datenbanken zu verwenden, wenn Hochgeschwindigkeitstransaktionen in Millisekunden benötigt werden. - Datenunveränderlichkeit
Die Unveränderlichkeit von Daten war schon immer einer der größten Nachteile der Blockchain. Es ist klar, dass mehrere Systeme davon profitieren, einschließlich Lieferkette, Finanzsysteme und so weiter. Es leidet jedoch unter der Tatsache, dass einmal geschriebene Daten nicht entfernt werden können. Jeder Mensch auf der Erde hat das Recht auf Privatsphäre. Wenn dieselbe Person jedoch eine digitale Plattform nutzt, die auf Blockchain-Technologie basiert, kann sie ihre Spur nicht aus dem System entfernen, wenn sie sie dort nicht haben möchte. Mit einfachen Worten, es gibt keine Möglichkeit, dass er seine Spur verwischen kann – er lässt Datenschutzrechte in Stücke gerissen. - Erfordert Expertenwissen
Die Implementierung und Verwaltung eines Blockchain-Projekts ist schwierig. Es erfordert gründliche Kenntnisse, um den gesamten Prozess zu durchlaufen. Aus diesem Grund ist es schwierig, Blockchain-Spezialisten oder Experten zu finden, da es viel Zeit und Mühe kostet, einen Blockchain-Experten auszubilden. Daher ist dieser Artikel ein guter Ausgangspunkt und eine gute Anleitung, wenn Sie bereits begonnen haben. - Interoperabilität
Mehrere Blockchain-Netzwerke, die hart daran arbeiten, das Distributed-Ledger-Problem zu lösen, machen es auf einzigartige Weise schwierig, sie in Beziehung zu setzen oder miteinander zu integrieren. Dies erschwert die Kommunikation zwischen verschiedenen Ketten. - Integration älterer Anwendungen
Viele Unternehmen und Anwendungen verwenden immer noch Legacy-Systeme und -Architekturen; Die Einführung der Blockchain-Technologie erfordert eine vollständige Überholung dieser Systeme, was meiner Meinung nach für viele von ihnen nicht machbar ist.
Blockchain entwickelt sich ständig weiter und reift, also wundern Sie sich nicht, wenn sich diese heute erwähnten Nachteile später in einen Profi verwandeln. Bitcoin, eine Kryptowährung, ist ein beliebtes Beispiel für eine Blockchain. Eine beliebte Blockchain, die neben der Bitcoin-Kryptowährung auf dem Vormarsch ist, ist die Ethereum-Blockchain. Bitcoin konzentriert sich auf Kryptowährungen, während Ethereum sich mehr auf intelligente Verträge konzentriert, die die Hauptantriebskraft für die neuen Technologieplattformen waren.
Empfohlene Lektüre : Bitcoin vs. Ethereum: Was ist der Unterschied?
Beginnen wir mit dem Aufbau unserer API
Mit einem soliden Verständnis von Blockchain schauen wir uns nun an, wie man eine Ethereum-Blockchain aufbaut und sie in Node.js in eine Standard-API integriert. Das ultimative Ziel ist es, ein gutes Verständnis dafür zu bekommen, wie dApps und Blockchain-Plattformen aufgebaut werden.
Die meisten dApps haben eine ähnliche Architektur und Struktur. Grundsätzlich haben wir einen Benutzer, der mit dem dApp-Frontend interagiert – entweder über das Web oder mobil –, der dann mit den Backend-APIs interagiert. Das Backend interagiert dann auf Anfrage mit den Smart Contracts oder der Blockchain über öffentliche Knoten; Diese führen entweder Node.js-Anwendungen aus oder das Backend verwendet Blockchain, indem es die Node.js-Software direkt ausführt. Es gibt noch so viele Dinge zwischen diesen Prozessen, von der Entscheidung, eine vollständig dezentralisierte Anwendung oder eine halbdezentralisierte Anwendung zu erstellen, bis hin zur Entscheidung, was dezentralisiert werden soll und wie private Schlüssel sicher gespeichert werden können.
Empfohlene Lektüre : Dezentrale Anwendungsarchitektur: Backend, Sicherheit und Entwurfsmuster
Dinge, die wir zuerst wissen sollten
Für dieses Tutorial werden wir versuchen, das Backend einer dezentralisierten Musikspeicher-App zu erstellen, die die Leistungsfähigkeit der Ethereum-Blockchain zum Speichern von Musik und zum Teilen für Downloads oder Streaming nutzt.
Die Grundstruktur der Anwendung, die wir zu erstellen versuchen, besteht aus drei Teilen:
- Authentifizierung , die per E-Mail erfolgt; Natürlich müssen wir der App ein verschlüsseltes Passwort hinzufügen.
- Speicherung von Daten , wobei die Musikdaten zunächst in ipfs gespeichert werden und die Speicheradresse in der Blockchain zum Abruf gespeichert wird.
- Abruf , wobei jeder authentifizierte Benutzer auf die gespeicherten Daten auf unserer Plattform zugreifen und diese verwenden kann.
Wir werden dies mit Node.js erstellen, aber Sie können auch mit Python oder einer anderen Programmiersprache erstellen. Wir werden auch sehen, wie man Mediendaten in IPFS speichert, die Adresse erhält und Funktionen schreibt, um diese Adresse zu speichern – und diese Adresse aus einer Blockchain mit der Programmiersprache Solidity abzurufen.
Hier sind einige Tools, die wir zum Erstellen oder Arbeiten mit Ethereum und Node.js zur Verfügung haben sollten.
- Node.js
Die erste Voraussetzung ist eine Node-Anwendung. Wir versuchen, eine Node.js-App zu erstellen, also brauchen wir einen Compiler. Bitte vergewissern Sie sich, dass Sie Node.js installiert haben – und laden Sie bitte die neueste langfristige Support-Binärdatei ( LTS ) herunter. - Trüffel-Suite
Truffle ist eine Auftragsentwicklungs- und Testumgebung sowie eine Asset-Pipeline für die Ethereum-Blockchain. Es bietet eine Umgebung zum Kompilieren, Pipelining und Ausführen von Skripts. Sobald Sie über die Entwicklung von Blockchain sprechen, ist Truffle eine beliebte Anlaufstelle. Informieren Sie sich über Truffle Suite auf Truffle Suite: Süße Tools für Smart Contracts. - Ganache-CLI
Ein weiteres Tool, das gut mit Truffle funktioniert, ist Ganache-CLI. Es wird vom Truffle Suite-Team erstellt und gewartet. Nach dem Erstellen und Kompilieren benötigen Sie einen Emulator, um Blockchain-Apps zu entwickeln und auszuführen und dann Smart Contracts bereitzustellen, die verwendet werden sollen. Ganache erleichtert es Ihnen, einen Vertrag in einem Emulator bereitzustellen, ohne tatsächliches Geld für Transaktionskosten, recycelbare Konten und vieles mehr zu verwenden. Lesen Sie mehr über Ganache CLI unter Ganache CLI und Ganache. - Remix
Remix ist wie eine Alternative zu Ganache, verfügt aber auch über eine GUI, um die Bereitstellung und das Testen von Ethereum Smart Contracts zu erleichtern. Sie können mehr darüber auf Remix – Ethereum IDE & Community erfahren. Alles, was Sie tun müssen, ist, https://remix.ethereum.org zu besuchen und die GUI zu verwenden, um intelligente Verträge zu schreiben und bereitzustellen. - Web3
Web3 ist eine Sammlung von Bibliotheken, mit denen Sie mit einem Ethereum-Knoten interagieren können. Dies können lokale oder entfernte Knoten des Vertrags über HTTP, IPC oder Web Sockets sein. Einführung in Web3.js · Ethereum Blockchain Developer Crash Course ist ein guter Ort, um etwas über Web3 zu lernen. - IPFS
Ein Kernprotokoll, das beim Erstellen von dApps verwendet wird. Das InterPlanetary File System (IPFS) ist ein Protokoll und ein Peer-to-Peer-Netzwerk zum Speichern und Teilen von Daten in einem verteilten Dateisystem. IPFS Powers the Distributed Web erklärt mehr über IPFS und wie es normalerweise verwendet wird.
Erstellen einer Backend-API von Grund auf neu
Also müssen wir zuerst ein Backend erstellen, das verwendet werden soll, und wir verwenden Node.js. Wenn wir eine neue Node.js-API erstellen möchten, initialisieren wir zunächst ein npm-Paket. Wie Sie wahrscheinlich wissen, steht npm für Node Package Manager und wird mit der Node.js-Binärdatei vorgepackt geliefert. Also erstellen wir einen neuen Ordner und nennen ihn „Blockchain-Musik“ . Wir öffnen das Terminal in diesem Ordnerverzeichnis und führen dann den folgenden Befehl aus:
$ npm init -y && touch server.js routes.js
Dadurch wird das Projekt mit einer Datei „ package.json “ gestartet und alle Eingabeaufforderungen mit „ Ja “ beantwortet. Dann erstellen wir auch eine server.js -Datei und eine routes.js -Datei zum Schreiben der routes
in der API.
Nach all dem müssen Sie Pakete installieren, die wir benötigen, um unseren Build einfach und unkompliziert zu gestalten. Dieser Prozess ist kontinuierlich, dh Sie können jederzeit während der Entwicklung Ihres Projekts ein Paket installieren.
Lassen Sie uns die wichtigsten installieren, die wir gerade brauchen:
- Express.js
- @Trüffel/Vertrag
- Truffle.js
- web3.js
- dotenv
-
short-id
- MongoDB
- Knotenmon
Sie müssen Truffle.js auch global installieren, damit Sie es überall in Ihrer lokalen Umgebung verwenden können. Wenn Sie alle auf einmal installieren möchten, führen Sie den folgenden Code in Ihrem Terminal aus:
$ npm install nodemon truffle-contract dotenv mongodb shortid express web3 --save && npm install truffle -g
Das Flag --save
dient zum Speichern des Paketnamens in der Datei „ package.json “. Das Flag -g
dient dazu, dieses spezielle Paket global zu speichern, damit wir es in jedem Projekt verwenden können, an dem wir arbeiten werden.
Anschließend erstellen wir eine .env -Datei, in der wir unseren geheimen URI der MongoDB-Datenbank zur Verwendung speichern können. Dazu führen wir touch.env im Terminal aus. Wenn Sie noch kein Datenbankkonto bei MongoDB haben, beginnen Sie zuerst mit der MongoDB-Seite.
Das dotenv -Paket exportiert unsere gespeicherte Variable in die Node.js-Prozessumgebung. Bitte stellen Sie sicher, dass Sie die .env -Datei nicht pushen, wenn Sie sie in öffentliche Repositories pushen, um zu vermeiden, dass Ihre Passwörter und privaten Daten preisgegeben werden.
Als Nächstes müssen wir Skripte für die Build- und Entwicklungsphasen unseres Projekts in unsere Datei „ package.json “ einfügen. Aktuell sieht unsere package.json so aus:
{ "name": "test", "version": "1.0.0", "description": "", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1", "socket.io": "^2.3.0", "truffle-contract": "^4.0.31", "web3": "^1.3.0" } }
Wir fügen dann der Datei package.json ein Startskript hinzu, um den Nodemon -Server zu verwenden, sodass bei jeder Änderung der Server selbst neu gestartet wird, und ein Build-Skript, das den Node-Server direkt verwendet, könnte so aussehen:
{ "name": "test", "version": "1.0.0", "description": "", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon server.js", "build": "node server.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1", "socket.io": "^2.3.0", "truffle-contract": "^4.0.31", "web3": "^1.3.0" } }
Als nächstes müssen wir Truffle für die Verwendung in unserem Smart Contract initialisieren, indem wir das Truffle-Paket verwenden, das wir zuvor global installiert haben. Im selben Ordner unserer Projekte führen wir den folgenden Befehl in unserem Terminal aus:
$ truffle init
Dann können wir damit beginnen, unseren Code in unsere server.js -Datei zu schreiben. Auch hier versuchen wir, eine einfache dezentrale Musikshop-App zu erstellen, in der Kunden Musik hochladen können, auf die jeder andere Benutzer zugreifen und die sie anhören kann.
Unsere server.js sollte sauber sein, um Komponenten einfach zu koppeln und zu entkoppeln, also werden Routen und andere Funktionalitäten in andere Dateien wie die routes.js eingefügt . Unser Beispiel server.js könnte sein:
require('dotenv').config(); const express= require('express') const app =express() const routes = require('./routes') const Web3 = require('web3'); const mongodb = require('mongodb').MongoClient const contract = require('truffle-contract'); app.use(express.json()) mongodb.connect(process.env.DB,{ useUnifiedTopology: true },(err,client)=>{ const db =client.db('Cluster0') //home routes(app,db) app.listen(process.env.PORT || 8082, () => { console.log('listening on port 8082'); }) })
Im Grunde importieren wir oben die Bibliotheken, die wir benötigen, mit require
, fügen dann eine Middleware hinzu, die die Verwendung von JSON in unserer API mit app.use
, verbinden uns dann mit unserer MongoDB-Datenbank und erhalten den Datenbankzugriff, und dann geben wir an, welcher Datenbankcluster Wir versuchen, darauf zuzugreifen (für dieses Tutorial ist es „Cluster0“ ). Danach rufen wir die Funktion auf und importieren sie aus der Routendatei . Schließlich hören wir Port 8082
auf Verbindungsversuche.
Diese server.js -Datei ist nur ein Barebone, um die Anwendung zu starten. Beachten Sie, dass wir routes.js importiert haben. Diese Datei enthält die Routenendpunkte für unsere API. Wir haben auch die Pakete, die wir zur Verwendung benötigten, in die Datei server.js importiert und initialisiert.
Wir werden fünf Endpunkte für den Benutzerverbrauch erstellen:
- Registrierungsendpunkt für die Registrierung von Benutzern nur per E-Mail. Idealerweise würden wir dies mit einer E-Mail-Adresse und einem Passwort tun, aber da wir nur jeden Benutzer identifizieren möchten, werden wir uns der Kürze dieses Tutorials halber nicht mit Passwortsicherheit und Hashing befassen.
POST /register Requirements: email
- Anmeldeendpunkt für Benutzer per E-Mail.
POST /login Requirements: email
- Upload-Endpunkt für Benutzer – die API, die die Daten der Musikdatei abruft. Das Frontend konvertiert die MP3/WAV-Dateien in einen Audiopuffer und sendet diesen Puffer an die API.
POST /upload Requirements: name, title of music, music file buffer or URL stored
- Greifen Sie auf den Endpunkt zu, der die Musikpufferdaten jedem registrierten Benutzer zur Verfügung stellt, der sie anfordert, und aufzeichnet, wer darauf zugegriffen hat.
GET /access/{email}/{id} Requirements: email, id
- Wir möchten auch den Zugriff auf die gesamte Musikbibliothek ermöglichen und die Ergebnisse an einen registrierten Benutzer zurückgeben.
GET /access/{email} Requirements: email
Dann schreiben wir unsere Routenfunktionen in unsere Datei routes.js . Wir nutzen die Funktionen zum Speichern und Abrufen der Datenbank und stellen dann sicher, dass wir die Routenfunktion am Ende der Datei exportieren, damit sie in eine andere Datei oder einen anderen Ordner importiert werden kann.
const shortid = require('short-id') function routes(app, db){ app.post('/register', (req,res)=>{ let email = req.body.email let idd = shortid.generate() if(email){ db.findOne({email}, (err, doc)=>{ if(doc){ res.status(400).json({"status":"Failed", "reason":"Already registered"}) }else{ db.insertOne({email}) res.json({"status":"success","id":idd}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.post('/login', (req,res)=>{ let email = req.body.email if(email){ db.findOne({email}, (err, doc)=>{ if(doc){ res.json({"status":"success","id":doc.id}) }else{ res.status(400).json({"status":"Failed", "reason":"Not recognised"}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.post('/upload', (req,res)=>{ let buffer = req.body.buffer let name = req.body.name let title = req.body.title if(buffer && title){ }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.get('/access/:email/:id', (req,res)=>{ if(req.params.id && req.params.email){ }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) } module.exports = routes
Innerhalb dieser route
haben wir viele andere Funktionen, die sowohl innerhalb der app
als auch der db
Parameter aufgerufen werden. Dies sind die API-Endpunktfunktionen, mit denen Benutzer einen Endpunkt in der URL angeben können. Letztendlich wählen wir eine dieser auszuführenden Funktionen aus und liefern Ergebnisse als Antwort auf eingehende Anfragen.
Wir haben vier Hauptendpunktfunktionen:
-
get
: zum Lesen von Datensatzoperationen -
post
: zum Erstellen von Datensatzoperationen -
put
: zum Aktualisieren von Datensatzoperationen -
delete
: zum Löschen von Aufzeichnungsvorgängen
In dieser routes
haben wir die get
und post
Operationen verwendet. Wir verwenden post
für Registrierungs-, Anmelde- und Uploadvorgänge und get
für den Zugriff auf die Datenvorgänge. Weitere Erläuterungen dazu finden Sie in Jamie Corkhills Artikel „How To Get Started With Node: An Introduction To APIs, HTTP And ES6+ JavaScript“.
Im obigen Code sehen wir auch einige Datenbankoperationen wie in der Registerroute . Wir haben die E-Mail eines neuen Benutzers mit db.createa
gespeichert und die E-Mail in der Anmeldefunktion mit db.findOne
. Nun, bevor wir das alles tun können, müssen wir eine Sammlung oder Tabelle mit der Methode db.collection
. Genau das werden wir als nächstes behandeln.
Hinweis : Weitere Informationen zu den Datenbankvorgängen in MongoDB finden Sie in der Dokumentation zu Mongo-Shell-Methoden.
Aufbau eines einfachen Blockchain Smart Contract mit Solidität
Jetzt schreiben wir einen Blockchain-Vertrag in Solidity (das ist die Sprache, in der Smart Contracts geschrieben sind), um unsere Daten einfach zu speichern und abzurufen, wenn wir sie brauchen. Die Daten, die wir speichern möchten, sind die Musikdateidaten, was bedeutet, dass wir die Musik auf IPFS hochladen und dann die Adresse des Puffers in einer Blockchain speichern müssen.
Zunächst legen wir eine neue Datei im Vertragsordner an und nennen diese Inbox.sol . Um einen Smart Contract zu schreiben, ist es hilfreich, Solidity gut zu verstehen, aber es ist nicht schwierig, da es JavaScript ähnelt.
Hinweis : Wenn Sie mehr über Solidity erfahren möchten, habe ich am Ende des Artikels einige Ressourcen hinzugefügt, um Ihnen den Einstieg zu erleichtern.
pragma solidity ^0.5.0; contract Inbox{ //Structure mapping (string=>string) public ipfsInbox; //Events event ipfsSent(string _ipfsHash, string _address); event inboxResponse(string response); //Modifiers modifier notFull (string memory _string) { bytes memory stringTest = bytes(_string); require(stringTest.length==0); _; } // An empty constructor that creates an instance of the conteact constructor() public{} //takes in receiver's address and IPFS hash. Places the IPFSadress in the receiver's inbox function sendIPFS(string memory _address, string memory _ipfsHash) notFull(ipfsInbox[_address]) public{ ipfsInbox[_address] = _ipfsHash; emit ipfsSent(_ipfsHash, _address); } //retrieves hash function getHash(string memory _address) public view returns(string memory) { string memory ipfs_hash=ipfsInbox[_address]; //emit inboxResponse(ipfs_hash); return ipfs_hash; } }
In unserem Vertrag haben wir zwei Hauptfunktionen: die sendIPFS
und die getHash
Funktion. Bevor wir über die Funktionen sprechen, können wir sehen, dass wir zuerst einen Vertrag namens Inbox
definieren mussten. Innerhalb dieser Klasse haben wir Strukturen, die im ipfsInbox
Objekt verwendet werden (zuerst Ereignisse, dann Modifikatoren).
Nachdem wir die Strukturen und Ereignisse definiert haben, müssen wir den Vertrag initialisieren, indem wir die constructor
aufrufen. Dann haben wir drei Funktionen definiert. (Die Funktion checkInbox
wurde im Test zum Testen der Ergebnisse verwendet.)
sendIPFS
gibt der Benutzer die Kennung und die Hash-Adresse ein, nach der sie in der Blockchain gespeichert werden. Die getHash
Funktion ruft die Hash-Adresse ab, wenn ihr der Bezeichner gegeben wird. Auch hier ist die Logik dahinter, dass wir die Musik letztendlich in IPFS speichern wollen. Um zu testen, wie es funktioniert, können Sie zu einer Remix-IDE wechseln, Ihren Vertrag kopieren, einfügen und testen sowie alle Fehler debuggen und erneut ausführen (hoffentlich wird es nicht benötigt!).
Nachdem wir getestet haben, dass unser Code im Remix korrekt funktioniert, fahren wir mit der lokalen Kompilierung mit der Truffle-Suite fort. Aber zuerst müssen wir einige Änderungen an unseren Dateien vornehmen und unseren Emulator mit ganache-cli
einrichten:
Lassen Sie uns zuerst ganache-cli
installieren. Führen Sie im selben Verzeichnis den folgenden Befehl in Ihrem Terminal aus:
$ npm install ganache-cli -g
Dann öffnen wir ein weiteres Terminal und führen einen weiteren Befehl im selben Ordner aus:
$ ganache-cli
Dadurch wird der Emulator für unseren Blockchain-Vertrag gestartet, um eine Verbindung herzustellen und zu funktionieren. Minimieren Sie das Terminal und fahren Sie mit dem anderen Terminal fort, das Sie verwendet haben.
Gehen Sie nun zur Datei truffle.js , wenn Sie Linux/Mac OS oder truffle-config.js unter Windows verwenden, und ändern Sie diese Datei so, dass sie wie folgt aussieht:
const path = require("path"); module.exports = { // to customize your Truffle configuration! contracts_build_directory: path.join(__dirname, "/build"), networks: { development: { host: "127.0.0.1", port: 8545, network_id: "*" //Match any network id } } };
Grundsätzlich haben wir den Pfad des Build-Ordners hinzugefügt, in dem der Smart Contract in JSON-Dateien konvertiert wird. Dann haben wir auch das Netzwerk angegeben, das Truffle für die Migration verwenden soll.
Erstellen Sie dann ebenfalls im Migrationsordner eine neue Datei mit dem Namen 2_migrate_inbox.js und fügen Sie den folgenden Code in die Dateien ein:
var IPFSInbox = artifacts.require("./Inbox.sol"); module.exports = function(deployer) { deployer.deploy(IPFSInbox); };
Wir haben dies getan, um die Vertragsdatei zu erhalten und sie automatisch in einem JSON bereitzustellen, indem wir die deployer
Funktion während der Truffle-Migration verwenden.
Nach den obigen Änderungen führen wir aus:
$ truffle compile
Wir sollten am Ende einige Meldungen sehen, die eine erfolgreiche Kompilierung anzeigen, wie zum Beispiel:
> Compiled successfully using: - solc: 0.5.16+commit.9c3226ce.Emscripten.clang
Als nächstes migrieren wir unseren Vertrag, indem wir Folgendes ausführen:
$ truffle migrate
Wenn wir unsere Verträge erfolgreich migriert haben, sollten wir am Ende so etwas haben:
Summary ======= > Total deployments: 1 > Final cost: 0.00973432 ETH
Und wir sind fast fertig! Wir haben unsere API mit Node.js erstellt und auch unseren Smart Contract eingerichtet und erstellt.
Wir sollten auch Tests für unseren Vertrag schreiben, um das Verhalten unseres Vertrags zu testen und sicherzustellen, dass es das gewünschte Verhalten ist. Die Tests werden normalerweise geschrieben und in den test
gelegt. Ein Beispieltest, der in eine Datei namens InboxTest.js geschrieben wurde, die im Testordner erstellt wurde, lautet:
const IPFSInbox = artifacts.require("./Inbox.sol") contract("IPFSInbox", accounts =>{ it("emit event when you send a ipfs address", async()=>{ //ait for the contract const ipfsInbox = await IPFSInbox.deployed() //set a variable to false and get event listener eventEmitted = false //var event = () await ipfsInbox.ipfsSent((err,res)=>{ eventEmitted=true }) //call the contract function which sends the ipfs address await ipfsInbox.sendIPFS(accounts[1], "sampleAddress", {from: accounts[0]}) assert.equal(eventEmitted, true, "sending an IPFS request does not emit an event") }) })
Also führen wir unseren Test durch, indem wir Folgendes ausführen:
$ truffle test
Es testet unseren Vertrag mit den Dateien im Testordner und zeigt die Anzahl der bestandenen und nicht bestandenen Tests an. Für dieses Tutorial sollten wir Folgendes erhalten:
$ truffle test Using network 'development'. Compiling your contracts... =========================== > Compiling .\contracts\Inbox.sol > Artifacts written to C:\Users\Ademola\AppData\Local\Temp\test--2508-n0vZ513BXz4N > Compiled successfully using: — solc: 0.5.16+commit.9c3226ce.Emscripten.clang Contract: IPFSInbox √ emit event when you send an ipfs address (373ms) 1 passing (612ms)
Integrieren des Smart Contract in die Backend-API mithilfe von Web3
Wenn Sie Tutorials sehen, sehen Sie meistens dezentrale Apps, die entwickelt wurden, um das Frontend direkt in die Blockchain zu integrieren. Aber es gibt Zeiten, in denen auch die Integration in das Backend erforderlich ist, z. B. bei der Verwendung von Backend-APIs und -Diensten von Drittanbietern oder bei der Verwendung von Blockchain zum Erstellen eines CMS.
Die Verwendung von Web3 ist für diese Sache sehr wichtig, da es uns hilft, auf entfernte oder lokale Ethereum-Knoten zuzugreifen und sie in unseren Anwendungen zu verwenden. Bevor wir fortfahren, werden wir die lokalen und entfernten Ethereum-Knoten besprechen. Die lokalen Knoten sind die Knoten, die auf unserem System mit Emulatoren wie ganache-cli
bereitgestellt werden, aber ein Remote-Knoten ist einer, der auf Online-Faucets/Plattformen wie ropsten oder rinkeby bereitgestellt wird . Um tiefer einzutauchen, können Sie einem Tutorial zur Bereitstellung auf Ropsten folgen, einer 5-Minuten-Anleitung zur Bereitstellung von Smart Contracts mit Truffle und Ropsten, oder Sie können den Truffle-Wallet-Anbieter verwenden und über An Easier Way to Deploy Your Smart Contracts bereitstellen.
Wir verwenden ganache-cli
in diesem Tutorial, aber wenn wir auf ropsten bereitstellen, hätten wir unsere Vertragsadresse irgendwo kopieren oder speichern sollen, z. B. in unserer .env-Datei, und dann mit der Aktualisierung der server.js -Datei fortfahren, web3 importieren, importieren den migrierten Vertrag und richten Sie eine Web3-Instanz ein.
require('dotenv').config(); const express= require('express') const app =express() const routes = require('./routes') const Web3 = require('web3'); const mongodb = require('mongodb').MongoClient const contract = require('truffle-contract'); const artifacts = require('./build/Inbox.json'); app.use(express.json()) if (typeof web3 !== 'undefined') { var web3 = new Web3(web3.currentProvider) } else { var web3 = new Web3(new Web3.providers.HttpProvider('https://localhost:8545')) } const LMS = contract(artifacts) LMS.setProvider(web3.currentProvider) mongodb.connect(process.env.DB,{ useUnifiedTopology: true }, async(err,client)=>{ const db =client.db('Cluster0') const accounts = await web3.eth.getAccounts(); const lms = await LMS.deployed(); //const lms = LMS.at(contract_address) for remote nodes deployed on ropsten or rinkeby routes(app,db, lms, accounts) app.listen(process.env.PORT || 8082, () => { console.log('listening on port '+ (process.env.PORT || 8082)); }) })
In der Datei server.js prüfen wir, ob die web3-Instanz bereits initialisiert ist. Wenn nicht, initialisieren wir es auf dem Netzwerkport, den wir zuvor definiert haben ( 8545
). Dann erstellen wir einen Vertrag basierend auf der migrierten JSON-Datei und dem truffle-contract
Paket und setzen den Vertragsanbieter auf den Web3-Instanzanbieter, der inzwischen initialisiert worden sein muss.
Wir erhalten dann Konten von web3.eth.getAccounts
. Für die Entwicklungsphase rufen wir die bereitgestellte Funktion in unserer Vertragsklasse auf, die ganache-cli
– das noch läuft – auffordert, uns eine zu verwendende Vertragsadresse zu geben. Aber wenn wir unseren Vertrag bereits auf einem entfernten Knoten bereitgestellt haben, rufen wir eine Funktion auf, die die Adresse als Argument eingibt. Die Beispielfunktion ist unterhalb der definierten lms
-Variablen in unserem obigen Code kommentiert. Dann rufen wir die routes
-Funktion auf und geben die App-Instanz, die Datenbankinstanz, die Vertragsinstanz ( lms
) und die Kontodaten als Argumente ein. Schließlich hören wir auf Anfragen auf Port 8082
.
Außerdem sollten wir inzwischen das MongoDB-Paket installiert haben, da wir es in unserer API als unsere Datenbank verwenden. Sobald wir das haben, gehen wir auf die Routenseite, wo wir die im Vertrag definierten Methoden verwenden, um Aufgaben wie das Speichern und Abrufen der Musikdaten zu erledigen.
Am Ende sollte unsere routes.js so aussehen:
const shortid = require('short-id') const IPFS =require('ipfs-api'); const ipfs = IPFS({ host: 'ipfs.infura.io', port: 5001,protocol: 'https' }); function routes(app, dbe, lms, accounts){ let db= dbe.collection('music-users') let music = dbe.collection('music-store') app.post('/register', (req,res)=>{ let email = req.body.email let idd = shortid.generate() if(email){ db.findOne({email}, (err, doc)=>{ if(doc){ res.status(400).json({"status":"Failed", "reason":"Already registered"}) }else{ db.insertOne({email}) res.json({"status":"success","id":idd}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.post('/login', (req,res)=>{ let email = req.body.email if(email){ db.findOne({email}, (err, doc)=>{ if(doc){ res.json({"status":"success","id":doc.id}) }else{ res.status(400).json({"status":"Failed", "reason":"Not recognised"}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.post('/upload', async (req,res)=>{ let buffer = req.body.buffer let name = req.body.name let title = req.body.title let id = shortid.generate() + shortid.generate() if(buffer && title){ let ipfsHash = await ipfs.add(buffer) let hash = ipfsHash[0].hash lms.sendIPFS(id, hash, {from: accounts[0]}) .then((_hash, _address)=>{ music.insertOne({id,hash, title,name}) res.json({"status":"success", id}) }) .catch(err=>{ res.status(500).json({"status":"Failed", "reason":"Upload error occured"}) }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.get('/access/:email', (req,res)=>{ if(req.params.email){ db.findOne({email: req.body.email}, (err,doc)=>{ if(doc){ let data = music.find().toArray() res.json({"status":"success", data}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.get('/access/:email/:id', (req,res)=>{ let id = req.params.id if(req.params.id && req.params.email){ db.findOne({email:req.body.email},(err,doc)=>{ if(doc){ lms.getHash(id, {from: accounts[0]}) .then(async(hash)=>{ let data = await ipfs.files.get(hash) res.json({"status":"success", data: data.content}) }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) } module.exports = routes
At the beginning of the routes file, we imported the short-id
package and ipfs-http-client
and then initialized IPFS with the HTTP client using the backend URL ipfs.infura.io
and port 5001
. This allowed us to use the IPFS methods to upload and retrieve data from IPFS (check out more here).
In the upload route, we save the audio buffer to IPFS which is better compared to just storing it on the blockchain for anyone registered or unregistered to use. Then we saved the address of the buffer in the blockchain by generating an ID and using it as an identifier in the sendIFPS
function. Finally, then we save all the other data associated with the music file to our database. We should not forget to update our argument in the routes function since we changed it in the server.js file.
In the access route using id
, we then retrieve our data by getting the id
from the request, using the id
to access the IPFS hash address, and then access the audio buffer using the address. But this requires authentication of a user by email which is done before anything else.
Phew, we're done ! Right now we have an API that can receive requests from users, access a database, and communicate to a node that has the software running on them. We shouldn't forget that we have to export our function with module.exports
though!
As we have noticed, our app is a decentralized app . However, it's not fully decentralized as we only stored our address data on the blockchain and every other piece of data was stored securely in a centralized database which is the basis for semi-dApps . So the consumption of data can be done directly via request or using a frontend application in JavaScript to send fetch requests.
Our music store backend app can now safely store music data and provide access to anyone who needs to access it, provided it is a registered user. Using blockchain for music sharing makes it cheaper to store music data while focusing on connecting artists directly with users, and perhaps it could help them generate revenue that way. This wouldn't require a middleman that uses royalty; instead, all of the revenue would go to the artist as users request their music to either download or stream. A good example of a music streaming application that uses blockchain just like this is Opus OPUS: Decentralized music sharing platform. However, there are also a few others like Musicoin, Audius, and Resonate.
Was als nächstes?
The final thing after coding is to start our server by running npm run start
or npm run build
and test our backend endpoints on either the browser or with Postman. After running and testing our API we could add more features to our backend and blockchain smart contract. If you'd like to get more guidance on that, please check the further reading section for more articles.
It's worth mentioning that it is critical to write unit and integration tests for our API to ensure correct and desirable behaviors. Once we have all of that done, we can deploy our application on the cloud for public use. This can be done on its own with or without adding a frontend (microservices) on Heroku, GCP, or AWS for public use. Happy coding!
Note : You can always check my repo for reference. Also, please note that the .env file containing the MongoDB database URI is included for security reasons.
Further Reading And Related Resources
- “How to Build Ethereum Dapp with React.js: Complete Step-By-Step Guide,” Gregory McCubbin
- “Ethereum + IPFS + React DApp Tutorial Pt. 1,” Alexander Ma
- “Ethereum Development with Go,” Miguel Mota
- “Create your first Ethereum dAPP with Web3 and Vue.JS (Part 1),” Nico Vergauwen
- “Deploy a Smart Contract on Ethereum with Python, Truffle and web3py,” Gabriel Saldanha
- “Why Use Blockchain Technology?,” Bernard Marr
- “How To Build Your Own Blockchain Using Node.js,” DevTeam.Space
- “How To Build A Blockchain App With Ethereum, Web3.js & Solidity Smart Contracts,” Gregory McCubbin
- “How To Build A Simple Cryptocurrency Blockchain In Node.js,” Alfrick Opidi
- “How Blockchain Technology Is Going To Revolutionize Ecommerce,” Sergii Shanin
- “4 Ways Blockchain Will Transform Higher Education — Smarter With Gartner,” Susan Moore
- “How To Learn Solidity: The Ultimate Ethereum Coding Tutorial,” Ryan Molecke
- “Developing Ethereum Smart Contracts For Beginners,” Coursetro
- “Learn about Ethereum,” Ethereum official site