Erstellen Sie ein privates Netzwerk mit Ethereum Geth in Docker-Containern



Wenn Sie ein privates Ethereum-Netzwerk basierend auf Geth bereitstellen müssen, können Sie dazu beispielsweise Netzwerkknoten auf physischen Servern oder virtuellen Maschinen erstellen. Es ist jedoch viel einfacher, Geth-Container aus dem Docker-Hub-Repository zu verwenden. In diesem Fall können Sie ein ganzes Netzwerk von Knoten sogar auf einer virtuellen Maschine oder auf einem physischen Server installieren.

In diesem Artikel erfahren Sie, wie Sie Docker auf einem Server installieren, auf dem Debian 9 (virtuell oder physisch) ausgeführt wird, wie Sie mit Geth mehrere Container erstellen und in ein privates Netzwerk integrieren. Wir werden ein Beispielskript für Node.js geben, das auf Geth-Knoten zugreift, die in Containern arbeiten.

Installieren Sie Docker


Die Installation von Docker wird auf der offiziellen Website beschrieben. Für Debian 9 und 10 finden Sie detaillierte Anweisungen unter https://docs.docker.com/install/linux/docker-ce/debian/ .

Installieren Sie Docker
Aktualisieren Sie zunächst die Pakete:

# apt-get update 

Installieren Sie als Nächstes die erforderlichen Pakete mit dem folgenden Befehl:

 # apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common 

Fügen Sie den offiziellen GPG-Schlüssel hinzu:

 # curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - 

Stellen Sie sicher, dass Sie den Schlüssel mit dem Fingerabdruck 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88 erhalten:

 # apt-key fingerprint 0EBFCD88 pub 4096R/0EBFCD88 2017-02-22 Key fingerprint = 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88 uid Docker Release (CE deb) docker@docker.com sub 4096R/F273FCD8 2017-02-22 

Fügen Sie ein stabiles Docker-Repository hinzu:

 # add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" 

Aktualisieren Sie die Pakete und installieren Sie Docker:

 # apt-get update # apt-get install docker-ce docker-ce-cli containerd.io 

Jetzt muss nur noch überprüft werden, ob alles richtig gemacht wurde. Führen Sie dazu das (Image) Hallo-Welt-Image aus:

 # docker run hello-world 

Dieser Befehl lädt das gewünschte Image herunter und führt es zur Ausführung aus. Wie zu erwarten, wird auf der Konsole die Meldung "Hallo von Docker!" Angezeigt.

Wie Sie sehen, nichts kompliziertes! Jetzt können Sie ein privates Geth-Netzwerk mit Knoten erstellen, die in Containern ausgeführt werden.

Erstellen Sie Benutzer, Verzeichnisse und Dateien


Erstellen Sie ein Buch auf dem Server des Benutzers und in den folgenden Unterverzeichnissen in seinem Basisverzeichnis:

 /home/book/dock-test /home/book/dock-test/distr 

Als nächstes erstellen Sie im Verzeichnis / home / book / dock-test eine Docker-Datei:

Listing 1. Datei / home / book / dock-test / Dockerfile
 FROM ubuntu:16.04 LABEL version="1.0" LABEL maintainer="alexandre@frolov.pp.ru" ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install --yes software-properties-common RUN add-apt-repository ppa:ethereum/ethereum RUN apt-get update && apt-get install --yes geth RUN adduser --disabled-login --gecos "" eth_book COPY distr /home/eth_book/distr RUN chown -R eth_book:eth_book /home/eth_book/distr USER eth_book WORKDIR /home/eth_book RUN geth --nousb init distr/genesis.json ENTRYPOINT bash 


Diese Datei wird beim Erstellen von Docker-Containern verwendet.

Sie müssen auch die Datei /home/book/dock-test/distr/genesis.json erstellen, die zum Initialisieren der Ethereum-Netzwerkknoten erforderlich ist:

Listing 2. Datei /home/book/dock-test/distr/genesis.json
 { "config": { "chainId": 98760, "homesteadBlock": 0, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0 }, "difficulty": "10", "gasLimit": "5100000", "alloc": {} } 


Hier setzen wir die Kennung unseres privaten Netzwerks auf 98760. Um das Mining zu vereinfachen, haben wir im Schwierigkeitsgrad den Wert 10 angegeben, damit wir auf virtuellen Maschinen mit relativ wenig Arbeitsspeicher (z. B. 4 GB) arbeiten können.

Erstellen Sie ein Netzwerk und Container


Damit unsere Knoten Daten miteinander austauschen können, erstellen wir ein Netzwerk zwischen Containern:

 # docker network create PRIVATENET 

Als nächstes müssen Sie das aktuelle Verzeichnis / home / book / dock-test erstellen, in dem sich die Docker-Datei befindet. Erstellen Sie dann die erforderliche Anzahl von Containern, z. B. drei:

 # docker build -t node01 . # docker build -t node02 . # docker build -t node03 . 

Das Erstellen des ersten Containers dauert relativ lange, weil Sie müssen die erforderlichen Bilder herunterladen. Die folgenden Container werden jedoch fast augenblicklich erstellt - verglichen mit der Geschwindigkeit, mit der virtuelle Maschinen erstellt werden, selbst durch das Klonen.

Öffnen Sie nun die vier Konsolenfenster. In drei Fällen werden wir mit Containern arbeiten, und im vierten Fall erhalten wir die Daten, die wir über Container und das Netzwerk benötigen.

Geben Sie im ersten Konsolenfenster den folgenden Befehl ein:

 # docker run --rm -it -p 8545:8545 --net=PRIVATENET node01 

Sie sehen eine Eingabeaufforderung wie:

 eth_book@304bf4f09063:~$ 

Geben Sie im zweiten und dritten Konsolenfenster die folgenden Befehle ein:

 # docker run --rm -it -p 8546:8546 --net=PRIVATENET node02 # docker run --rm -it -p 8547:8547 --net=PRIVATENET node03 

Erstellen von privaten Ethereum-Netzwerkknoten und -Konten


Im Moment haben wir drei Container mit Geth. Erstellen wir in jedem von ihnen den Knoten unseres privaten Ethereum-Netzwerks und -Kontos.

Geben Sie den Befehl in den ersten drei Konsolenfenstern ein:

 $ geth account new 

Sie müssen ein Passwort eingeben. Verwenden Sie zum Testen der Einfachheit halber auf jedem Knoten dasselbe Kennwort, notieren Sie es sich jedoch irgendwo. Wenn Sie das Kennwort vergessen, funktioniert die Wiederherstellung in keiner Weise.

Nach dem Erstellen der Konten in der Konsole werden öffentliche Schlüsseladressen angezeigt, die diesen ähnlich sind:

 Public address of the key: 0xc5Df10a76Bb559332c385F8cA789C0F37dD77A54 Public address of the key: 0x0C976006a5762779bA36AC590D1D8Ebac1Ca2981 Public address of the key: 0xaB627feab4e962222a3333F3b09182dF68bB9422 

Speichern Sie die Adressen (Sie werden andere haben) als Wir brauchen sie, um die Knoten laufen zu lassen.

Jetzt müssen Sie die Initialisierung der Knoten starten. Dies geschieht mit dem Befehl:

 $ geth --nousb init distr/genesis.json 

Geben Sie diesen Befehl in alle Konsolenfenster unserer Container ein. Die Option --nousb deaktiviert die gesamte Kommunikation mit USB-Geräten.

Geth-Knoten ausführen


Öffnen Sie nun nacheinander die einzelnen Konsolenfenster und führen Sie dort Geth mit den folgenden Befehlen aus.

Erstes Fenster:

 $ geth --identity="Node01" --etherbase "0xc5Df10a76Bb559332c385F8cA789C0F37dD77A54" --mine --minerthreads 1 --verbosity 3 --networkid 98760 --rpc --rpcaddr 127.0.0.1 --nousb --rpcapi="db,eth,net,web3,personal,web3" console 

Zweites Fenster:

 $ geth --identity="Node02" --etherbase "0x0C976006a5762779bA36AC590D1D8Ebac1Ca2981" --mine --minerthreads 1 --verbosity 3 --networkid 98760 --rpc --rpcaddr 127.0.0.1 --rpcport=8546 --nousb --rpcapi="db,eth,net,web3,personal,web3" console 

Drittes Fenster:

 $ geth --identity="Node03" --etherbase "0xaB627feab4e962222a3333F3b09182dF68bB9422" --mine --minerthreads 1 --verbosity 3 --networkid 98760 --rpc --rpcaddr 127.0.0.1 --rpcport=8547 --nousb --rpcapi="db,eth,net,web3,personal,web3" console 

In jedem der geöffneten Fenster werden Meldungen zur DAG-Generierung angezeigt:

 … INFO [12-19|17:57:44.072] Generating DAG in progress epoch=0 percentage=34 elapsed=29.740s INFO [12-19|17:57:44.898] Generating DAG in progress epoch=0 percentage=35 elapsed=30.566s INFO [12-19|17:57:45.671] Generating DAG in progress epoch=0 percentage=36 elapsed=31.339s … 

Warten Sie, bis die Generierung abgeschlossen ist. Danach unterscheiden sich eth.hashrate und eth.blockNumber von 0:

 > eth.hashrate 4 > eth.blockNumber 2 

Sie können den aktuellen Kontostand wie folgt überprüfen:

 > web3.fromWei( eth.getBalance(eth.coinbase) ) 

Beenden Sie Geth mit dem Befehl exit und starten Sie das Programm mit dem auf 1 gesetzten Parameter verbosity erneut, damit Sie sich nicht um Nachrichten über das Erstellen neuer Blöcke und anderer Nachrichten in Konsolenfenstern kümmern.

Netzwerkknoten


Zunächst sehen wir uns die Liste der laufenden Container an. Geben Sie im vierten Konsolenfenster den folgenden Befehl ein:

 # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fa70a5418618 node03 "/bin/sh -c bash" 2 hours ago Up 2 hours 0.0.0.0:8547->8547/tcp gifted_curran 49a028744b4b node02 "/bin/sh -c bash" 2 hours ago Up 2 hours 0.0.0.0:8546->8546/tcp reverent_wescoff 5a9ade2947eb node01 "/bin/sh -c bash" 2 hours ago Up 2 hours 0.0.0.0:8545->8545/tcp clever_ellis 

Hier werden für jeden Container die ID, der Bildname, der Containername und andere Informationen angezeigt.

Um Container in ein Netzwerk einzubinden, benötigen Sie die IP-Adressen der Container in unserem privaten PRIVATENET-Netzwerk. Sie können diese Adressen beispielsweise wie folgt über die Container-ID abrufen:

 # docker inspect 5a9ade2947eb | grep IPAddress "SecondaryIPAddresses": null, "IPAddress": "", "IPAddress": "172.21.0.2", 

Sie können auch den Docker-Befehl network inspect PRIVATENET verwenden:

Docker-Netzwerk inspizieren PRIVATENET
 [ { "Name": "PRIVATENET", "Id": "576ec7edba5b4c228740deaf7fabb5e2ba003d310086153dd7f15e2c7de0c1b2", "Created": "2019-12-20T11:52:07.90695857+03:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "172.21.0.0/16", "Gateway": "172.21.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "49a028744b4b6073f6dbca23e78625bc58fc0cdacadec7cded4bb0e888c7e37b": { "Name": "reverent_wescoff", "EndpointID": "11006b596b5a46df9bf9f95a9456784795d333a3e6901b15bd2db746fd4b5513", "MacAddress": "02:42:ac:15:00:03", "IPv4Address": "172.21.0.3/16", "IPv6Address": "" }, "5a9ade2947ebd8e55594ede9763aac71f5e6529c03e762ef723adb2c592c5ccd": { "Name": "clever_ellis", "EndpointID": "41ef69a0a93b5b1de495836028bac1742c303de92ffe42a0855ed32c93c28953", "MacAddress": "02:42:ac:15:00:02", "IPv4Address": "172.21.0.2/16", "IPv6Address": "" }, "fa70a54186185de01db3647e7333bf6c71250162fafefb78dbe9998e5ac93f34": { "Name": "gifted_curran", "EndpointID": "d368c032bc0886c27ad4895d1856e4f00cf1b25ce040f3b42393dbff778c18e5", "MacAddress": "02:42:ac:15:00:04", "IPv4Address": "172.21.0.4/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ] 

Wenn wir die von diesen Befehlen empfangenen Daten vergleichen, erstellen wir eine Liste mit IP-Adressen für unsere Container:

 node01 - 172.21.0.2 node02 - 172.21.0.3 node03 - 172.21.0.4 

Natürlich haben Sie eine andere Liste, und wenn Sie die Container neu starten, können sich diese Adressen ändern.

Starten Sie geth in allen Containern neu, nachdem Sie die Liste der Adressen erhalten haben, und geben Sie die Adresse Ihres Containers im Parameter --rpcaddr an. Sie können natürlich die Adresse 0.0.0.0 einstellen, aber dies ist aus Sicherheitsgründen schlecht - jeder oder alles kann sich mit dem Knoten verbinden. Es können zum Beispiel Bots sein, die versuchen, alle Gelder von diesen Knoten abzuheben und darauf warten, dass der Knoten entsperrt wird.

Um die Knoten zusammenzuführen, müssen Sie den Befehl admin.addPeer verwenden. Als Parameter für diesen Befehl müssen Sie die URL im Enode-Format übergeben. Rufen Sie diese URL für jeden Container mit dem Befehl admin.nodeInfo.enode ab:

 > admin.nodeInfo.enode "enode://0a84e562c9b22e43269b7dca215cf2ed8c20bbf35da67bae8d5ee81b36d8bbb69e3ec704b9b6f7501059fe861843a836b2fbab641f36616cdd77365b1a522d5b@62.152.63.28:30303?discport=1350" "enode://ee49f69e25c068e006fec4a8d74370370b1d2be9715b86eddd99f97a3a5a9c692a265ab7d01fb36410d59c3f6e2b253a22f652ecbf1941eef0b3f1d30b19a535@62.152.63.28:30303?discport=1345" "enode://156d43648b47078439c7481e54f697bbf1c6b6e762029ba2969f1556ceb94e51ad03f8bd2bed35f466073165810600f52925d155f0fceef832ae86fc39a8c135@62.152.63.28:30303?discport=1348" 

Empfangene Adressen speichern.

Um einen Knoten mit einem anderen zu verbinden, öffnen Sie das Konsolenfenster des ersten Knotens und geben Sie dort den folgenden Befehl ein:

 > admin.addPeer( "enode://0a84e562c9b22e43269b7dca215cf2ed8c20bbf35da67bae8d5ee81b36d8bbb69e3ec704b9b6f7501059fe861843a836b2fbab641f36616cdd77365b1a522d5b@172.21.0.3:30303") 

Hier haben wir die URL-Adresse übergeben, in der die IP-Adresse des verbundenen Hosts angegeben ist. Befolgen Sie das gleiche Verfahren auf anderen Netzwerkknoten.

Verwenden Sie den Befehl admin.peers, um zu überprüfen, ob die Verbindung hergestellt wurde. Wenn keine Verbindungen bestehen, gibt der Befehl ein leeres Ergebnis zurück:

 > admin.peers [] 

In unserem Fall zeigt der Befehl, dass der erste Knoten mit der Adresse 172.21.0.2 mit den Knoten mit den Adressen 172.21.0.3 und 172.21.0.4 verbunden ist:

Zeigen Sie das Ergebnis an, wenn Verbindungen bestehen
 > admin.peers [{ caps: ["eth/63", "eth/64"], enode: "enode://156d43648b47078439c7481e54f697bbf1c6b6e762029ba2969f1556ceb94e51ad03f8bd2bed35f466073165810600f52925d155f0fceef832ae86fc39a8c135@172.21.0.4:30303", id: "4dac1d10cb6ae8bfc1fdebd3f5334b24ee62ec38a50bc92c89104cfc3251b5fc", name: "Geth/Node03/v1.9.9-stable-01744997/linux-amd64/go1.13.4", network: { inbound: false, localAddress: "172.21.0.2:40652", remoteAddress: "172.21.0.4:30303", static: true, trusted: false }, protocols: { eth: { difficulty: 98414119, head: "0x6b31a5bb9cde06fab5a8cc1ae9b18bada30de0d1b76cb3286c1081e76dbf5b83", version: 64 } } }, { caps: ["eth/63", "eth/64"], enode: "enode://ee49f69e25c068e006fec4a8d74370370b1d2be9715b86eddd99f97a3a5a9c692a265ab7d01fb36410d59c3f6e2b253a22f652ecbf1941eef0b3f1d30b19a535@172.21.0.3:30303", id: "b74277d278c15317fa7f7fa492daca60492ea22053bfc53281dd0071eba1c16b", name: "Geth/Node02/v1.9.9-stable-01744997/linux-amd64/go1.13.4", network: { inbound: false, localAddress: "172.21.0.2:42576", remoteAddress: "172.21.0.3:30303", static: true, trusted: false }, protocols: { eth: { difficulty: 99041423, head: "0x0ec44735bbb425cb8db96103f52300dfaae1147ba0e03aa4892d041250ce4408", version: 64 } } }] 

Beachten Sie, dass der Befehl eth.blockNumber nach dem erfolgreichen Kombinieren und Synchronisieren der Knoten denselben Wert zurückgibt, wenn er in einem unserer drei Container gestartet wird.

Der Befehl web3.fromWei (eth.getBalance (eth.coinbase)) hingegen zeigt auf verschiedenen Knoten ein unterschiedliches Gleichgewicht, weil Jeder Knoten hat ein eigenes Konto.

Arbeiten Sie mit Hosts mithilfe von Node.js


In Listing 3 haben wir ein einfaches Skript vorgestellt, in dem Node.js ausgeführt wird. Auf der Konsole wird eine Liste der Konten für den angegebenen Knoten und deren Saldo angezeigt:

Listing 3. Datei / home / book / list_accounts.js
 var Web3 = require('web3') var web3 = new Web3(new Web3.providers.HttpProvider("http://172.21.0.2:8545")); web3.eth.getAccounts() .then(accList => { return accList; }) .then(function (accounts) { var balancePromeses = []; for(let i = 0; i < accounts.length; i++) { balancePromeses[i] = web3.eth.getBalance(accounts[i]); } Promise.all(balancePromeses).then(values => { for(let i = 0; i < values.length; i++) { console.log('Account: ', accounts[i], 'balance: ', values[i], 'wei, ', web3.utils.fromWei(values[i], 'ether'), 'ether'); } }); }) .catch(function (error) { console.error(error); }); 


Sie können dieses Skript in einem separaten Fenster ausführen, z. B. im vierten Konsolenfenster:

 # node list_accounts.js Account: 0x0C976006a5762779bA36AC590D1D8Ebac1Ca2981 balance: 3350000000000000000000 wei, 3350 ether 

Was weiter


Das Thema der Softwareentwicklung für Kryptowährungen im Allgemeinen und für Ethereum im Besonderen ist ziemlich faszinierend. Wenn Sie nach dem Lesen dieses Artikels Fragen haben und mehr erfahren möchten, lesen Sie mein Buch „Erstellen von Solidity-Smart-Verträgen für die Ethereum-Blockchain. Practical Guide “ , das im Liters Publishing House veröffentlicht wurde.

Möglicherweise benötigen Sie auch einen guten Docker-Spickzettel .

Für Kommentare und Ergänzungen zum Artikel und zum Buch wäre ich dankbar!

Source: https://habr.com/ru/post/de481052/


All Articles