Smart Contracts für die Ethereum-Blockchain

+ Kryptowährungen
+ TechDocs
+


Blockchain bezeichnet eine kontinuierlich erweiterbare Liste von Datensätzen, welche mittels kryptographischer Verfahren miteinander verkettet sind, so dass die Kette der Datensätze unveränderlich und fälschungssicher ist. Neue Transaktionen werden validiert und in Blöcke verpackt, und die Blöcke werden nach Durchlaufen eines Konsensus-Algorithmus an die Blockchain angehängt und an alle anderen Blockchain-Server gesendet.

Ethereum basiert auf einer öffentlichen Blockchain, die in einem dezentralen Peer-to-Peer-Netz auf vielen Ethereum-Servern als DLT betrieben wird. Ethereum beinhaltet die Kryptowährung Ether und ermöglicht darüber hinaus "Smart Contracts". Damit können Verträge programmiert werden, die elektronisch ausgeführt und überprüft werden. Dazu werden Skripte erstellt (meistens in der Programmiersprache Solidity) und in der Ethereum Virtual Machine (EVM) ausgeführt.
Dies eröffnet sehr vielfältige Möglichkeiten, beispielsweise basieren viele ICOs darauf. Allerdings muss bei der Programmierung von Smart Contracts besondere Vorsicht gelten: Einprogrammierte Sicherheitslücken können fatale Folgen haben, wie beim "The DAO Hack", der zum Ethereum-Hard-Fork "Ethereum Classic" führte.

Grundsätzliche Erläuterungen gibt es unter: Kryptowährungen, Bitcoin, Ethereum, Blockchain. Im Folgenden werden einige einfache Programmierbeispiele für Smart Contracts gezeigt.



Inhalt

  1. Basisinstallationen: Geth, Solc, private Test-Ethereum-Blockchain
  2. Erster Smart Contract: Hallo-Welt-Demo
  3. Mini-Token-Smart-Contract: MeinToken-Demo
  4. Remix Online Solidity Compiler als grafische Entwicklungsumgebung (GUI-IDE)
  5. Einen MeinToken-Transfer mit dem GUI-Tool Mist ausführen
  6. DApp-Webseite für den Smart Contract mit Node.js
  7. Transfer von Ether mit Web3j und Java
  8. Transfer von eigenen Smart-Contract-Tokens mit Web3j und Java
  9. DApp-Webseite für den Smart Contract mit Java
  10. Öffentliche Rinkeby-Test-Ethereum-Blockchain statt privater Blockchain
  11. Smart Contract in die öffentliche Rinkeby-Blockchain deployen
  12. DApp-Webseite für den Smart Contract in der Rinkeby-Blockchain
  13. Truffle für einfache Entwicklung und schnelle Tests
  14. Embark für einfache Entwicklung und schnelle Tests
  15. DApp-Webseite für den Smart Contract sowohl mit Truffle als auch mit Embark
  16. Verwendung des Oraclize-Dienstes für externe Informationsabfragen
  17. Analyse der Blöcke und Transaktionen
  18. Solidity-Plugin für JetBrains IntelliJ IDEA
  19. Doku



Basisinstallationen: Geth, Solc, private Test-Ethereum-Blockchain

Diese Demo zeigt:

Verwendet werden folgende Versionen:

Der folgende Text legt den Fokus auf Einfachheit und gute Nachvollziehbarkeit. Vorläufig werden nur Kommandozeilen-Tools eingesetzt. Auf grafische Tools wird weiter unten eingegangen.

In diesem Beispiel wird eine private nur auf dem eigenen PC existierende Ethereum-Blockchain eingerichtet. Wie eine öffentliche Ethereum-Blockchain verwendet werden kann, wird weiter unten gezeigt.

Die Kommandos sind für Windows dargestellt. Bei Verwendung von Linux oder Mac OS X genügt es häufig, in Pfadangaben "\" durch "/", in PATH-Angaben ";" durch ":" und bei Platzhaltern %MEINE_VARIABLE% durch $MEINE_VARIABLE zu ersetzen.

Führen Sie die im Folgenden beschriebenen Schritte aus.

  1. Wechseln Sie in Ihr bevorzugtes Workspace-Verzeichnis (z.B. \MeinWorkspace) und führen Sie folgende Kommandos aus:

    cd \MeinWorkspace

    mkdir EthereumDemo

    cd EthereumDemo

    mkdir solc

    mkdir src

    tree /F

  2. Installieren Sie solc (Solidity Compiler):
    Downloaden Sie von https://github.com/ethereum/solidity/releases die für Ihr Betriebssystem geeignete Installationsdatei, beispielsweise für Windows: solidity-windows.zip.
    Unter Windows entzippen Sie diese Zip-Datei in das Verzeichnis: \MeinWorkspace\EthereumDemo\solc.
    Für andere Betriebssysteme verfahren Sie entweder analog oder wie beschrieben unter: Installing the Solidity Compiler.

  3. Führen Sie im Kommandozeilenfenster aus:

    cd \MeinWorkspace\EthereumDemo

    solc\solc.exe --version

    solc\solc.exe --help

    Beide Kommandos müssen plausible Ergebnisse zeigen.

  4. Installieren Sie geth (Go Ethereum):
    Downloaden Sie von https://geth.ethereum.org/downloads/ eine für Ihr Betriebssystem geeignete Geth-Version, beispielsweise für Windows "Geth 1.8.2 for Windows".
    Verwenden Sie nicht die Geth-Versionen 1.8.0 und 1.8.1, weil es damit zum Web3j Issue 318 kommt.
    Für Windows erhalten Sie die Datei "geth-windows-amd64-1.8.2-b8b9f7f4.exe". Führen Sie diese Datei aus. Die Installation erweitert den Windows-Such-PATH um das Geth-Verzeichnis.
    Für andere Betriebssysteme verfahren Sie wie beschrieben unter: https://www.ethereum.org/cli oder https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum.

  5. Öffnen Sie ein neues Kommandozeilenfenster, damit Konfigurationsänderungen und PATH-Erweiterungen wirksam werden. Führen Sie darin aus:

    cd \MeinWorkspace\EthereumDemo

    geth version

    geth help

    Beide Kommandos müssen plausible Ergebnisse zeigen.

    Zu den Kommandozeilenoptionen von geth finden Sie auch eine Auflistung unter: Command Line Options.

  6. Genesis-Block:
    Um eine eigene private Test-Ethereum-Blockchain zu starten, wird eine manuelle Initialisierung des ersten Genesis-Blocks benötigt. Erstellen Sie im src-Unterverzeichnis die JSON-Datei:
    genesis-block.json

    {
        "alloc": {},
        "coinbase": "0x0000000000000000000000000000000000000000",
        "config": {},
        "difficulty": "0x4000",
        "extraData": "0x4711",
        "gasLimit": "0xffffffff",
        "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "nonce": "0x0000000000000042",
        "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "timestamp": "0x00"
    }
    

    Achten Sie beim Speichern darauf, dass die Datei mit Unix-Zeilenendezeichen und als ASCII-Datei ohne UTF-BOM gespeichert werden muss.

    Einige Hinweise zum Genesis-Block finden Sie unter: Creating The Genesis Block.

  7. Erstellen Sie den Genesis-Block, indem Sie ausführen:

    cd \MeinWorkspace\EthereumDemo

    geth --datadir "Private-Blockchain" init src/genesis-block.json

    Sie erhalten u.a.:

    Successfully wrote genesis state
    
  8. Start der eigenen Test-Ethereum-Blockchain (vorerst ohne Mining):
    Führen Sie aus (in einer Zeile):

    geth --networkid 77 --identity "MeineDevChain" --datadir "Private-Blockchain" --nodiscover --rpc --rpcapi "db,eth,net,web3,personal,txpool" --rpccorsdomain "*" console

    Sie erhalten u.a.:

    Starting peer-to-peer node
    HTTP endpoint opened: http://127.0.0.1:8545
    Welcome to the Geth JavaScript console!
    

    Und Sie erhalten die Geth-JavaScript-Console, in der Sie Geth-JavaScript-Kommandos eingeben können.

  9. Sehen Sie sich die Doku zu den web3.eth-Kommandos an: web3.eth 1.0 bzw. Web3 0.20.x JavaScript API. Fragen Sie die von Ihnen verwendete Web3.js-Version ab:

    web3.version.api

  10. Testen Sie, ob bereits Accounts existieren. Falls das Einfügen von Kommandos per Strg+V nicht funktioniert, versuchen Sie die rechte Maustaste, "Einfügen" und Return:

    web3.eth.accounts

    Sie erhalten eine leere Menge:

    []
    
  11. Account anlegen:
    Legen Sie einen Account an (denken Sie sich ein schwierigeres Passwort aus und merken Sie es sich gut):

    personal.newAccount( "Meine Ethereum-Test-Passphrase" )

    Sie erhalten eine 40-stellige Hex-Zahl als Account-Adresse, beispielsweise:

    "0x2f94831a57a96041064d9d0c24583b12f807f2a5"
    
  12. Testen Sie erneut auf vorhandene Accounts:

    web3.eth.accounts

    Diesmal erhalten Sie beispielsweise:

    ["0x2f94831a57a96041064d9d0c24583b12f807f2a5"]
    
  13. Kontostände abfragen:
    Erstellen Sie im src-Unterverzeichnis die JavaScript-Datei:
    checkAllBalances.js

    function checkAllBalances() {
       web3.eth.getAccounts( function( err, accounts ) {
          accounts.forEach( function( id ) {
             web3.eth.getBalance( id, function( err, balance ) {
                console.log( "" + id + ":\tbalance: " + web3.fromWei( balance, "ether" ) + " ether" );
             } );
          } );
       } );
    };
    checkAllBalances()
    
  14. Führen Sie in der Geth-JavaScript-Console aus:

    loadScript( 'src/checkAllBalances.js' )

    Sie erhalten:

    0x2f94831a57a96041064d9d0c24583b12f807f2a5:     balance: 0 ether
    
  15. Mining manuell starten:
    Führen Sie aus (führen Sie die einzelnen JavaScript-Kommandos nicht zu schnell hintereinander aus):

    miner.setEtherbase( web3.eth.accounts[0] )

    miner.start( 1 )

    Sie erhalten eine nicht endende Ausgabe von Mining-Kommandos:

    Starting mining operation
    Commit new mining work
    Successfully sealed new block
    mined potential block
    ...
    

    Falls bei Ihnen das Mining nicht startet: Manchmal kommt es vor, dass das Mining erst nach vielleicht 10 Minuten beginnt.

    Geben Sie dem Mining etwas Zeit, ca. eine Minute. Anschließend befinden sich auf dem Account Ether.

  16. Beenden Sie die Test-Ethereum-Blockchain:

    exit

  17. Start-Skript:
    Erstellen Sie im EthereumDemo-Projektverzeichnis die Batchdatei starte-Test-Ethereum-Blockchain.bat mit folgendem Inhalt (in einer Zeile):

    geth --networkid 77 --identity "MeineDevChain" --datadir "Private-Blockchain" --nodiscover --rpc --rpcapi "db,eth,net,web3,personal,txpool" --rpccorsdomain "*" --mine --minerthreads 1 console 2>>priv-geth.log

    Beachten Sie, dass diesmal per "--mine --minerthreads 1" das Mining automatisch aktiviert wird, und per "2>>priv-geth.log" die vielen Ausgaben in eine Logdatei umgeleitet werden.

  18. Start der eigenen Test-Ethereum-Blockchain inklusive Mining:
    Führen Sie aus:

    cd \MeinWorkspace\EthereumDemo

    starte-Test-Ethereum-Blockchain.bat

    Sie erhalten z.B.:

    Welcome to the Geth JavaScript console!
    instance: Geth/MeineDevChain/v1.8.2-stable-b8b9f7f4/windows-amd64/go1.9
    coinbase: 0x2f94831a57a96041064d9d0c24583b12f807f2a5
    at block: 1448 (Mon, 22 Jan 2018 12:53:13 CET)
     datadir: \MeinWorkspace\EthereumDemo\Private-Blockchain
     modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
    
  19. Führen Sie in der Geth-JavaScript-Console erneut aus:

    loadScript( 'src/checkAllBalances.js' )

    Diesmal erhalten Sie einen positiven Betrag, beispielsweise:

    0x2f94831a57a96041064d9d0c24583b12f807f2a5:     balance: 4711 ether
    
  20. Führen Sie zum Kennenlernen weitere Kommandos aus, beispielsweise:

    admin.datadir

    admin.nodeInfo

    eth

    eth.getBlock( "latest" )

    miner.getHashrate()

    personal.listAccounts

    txpool.content

    web3

    Sehen Sie sich die Erläuterungen zu den Management-Kommandos an.

  21. Beenden Sie die Test-Ethereum-Blockchain:

    exit

  22. Überprüfung der Keystore-Datei und der Verzeichnisstruktur:
    Führen Sie aus:

    dir \MeinWorkspace\EthereumDemo\Private-Blockchain\keystore

    Dort befindet sich die Keystore-Datei, beispielsweise:

    UTC--2018-01-22T09-50-58.520494400Z--2f94831a57a96041064d9d0c24583b12f807f2a5
    
  23. Die Projektstruktur sieht jetzt so aus (überprüfen Sie es unter Windows mit tree /F und unter Linux mit tree):

    [\MeinWorkspace\EthereumDemo]
     |- priv-geth.log
     |- starte-Test-Ethereum-Blockchain.bat
     |- [Private-Blockchain]
     |   |- history
     |   |- [geth]
     |   |   '- ...
     |   '- [keystore]
     |       '- UTC--2018-01-22T09-50-58...
     |- [solc]
     |   |- msvcp140.dll
     |   |- solc.exe
     |   '- soltest.exe
     '- [src]
         |- checkAllBalances.js
         '- genesis-block.json
    


Erster Smart Contract: Hallo-Welt-Demo

Diese Demo zeigt:

Auch in dieser Demo werden noch nur Kommandozeilen-Tools eingesetzt. Auf grafische Tools wird weiter unten eingegangen.

Führen Sie die im Folgenden beschriebenen Schritte aus.

  1. Alle oben unter Basisinstallationen: Geth, Solc, private Test-Ethereum-Blockchain beschriebenen Schritte müssen ausgeführt worden sein.

  2. Wechseln Sie in Ihr oben eingerichtetes EthereumDemo-Workspace-Verzeichnis (z.B. \MeinWorkspace\EthereumDemo):

    cd \MeinWorkspace\EthereumDemo

  3. Erstellen Sie im src-Unterverzeichnis das Solidity-Skript:
    Greeter.sol

    pragma solidity ^0.4.19;
    
    /* Hilfsklasse, damit der Smart Contract nach Benutzung entfernt werden kann */
    contract Mortal {
       /* Besitzer */
       address owner;
    
       /* Konstruktor, wird bei der Initialisierung aufgerufen */
       function Mortal() public {
          owner = msg.sender;
       }
    
       /* Entfernen des Contracts */
       function kill() public {
          if( msg.sender == owner ) selfdestruct( owner );
       }
    }
    
    /* Hauptanwendungsklasse, abgeleitet von Mortal */
    contract Greeter is Mortal {
       /* Zu speichernder Text */
       string greeting;
        
       /* Konstruktor, wird bei der Initialisierung aufgerufen */
       function Greeter( string _greeting ) public {
          greeting = _greeting;
       }
    
       /* Hauptanwendungsmethode, Wiedergabe des gespeicherten Texts */
       function greet() public constant returns( string ) {
          return greeting;
       }
    }
    

    Dies ist eine geringfügig erweiterte Version der Demo unter The Greeter. Dort finden Sie auch Kommentare zum Solidity-Sourcecode.

  4. Kompilieren Sie das Solidity-Skript:

    cd \MeinWorkspace\EthereumDemo

    solc\solc -o target --bin --abi --overwrite src/Greeter.sol

    dir target

    Sie erhalten das neue Verzeichnis "target" mit vier neuen Dateien:

    [\MeinWorkspace\EthereumDemo]
     |- priv-geth.log
     |- starte-Test-Ethereum-Blockchain.bat
     |- [Private-Blockchain]
     |   '- ...
     |- [solc]
     |   '- ...
     |- [src]
     |   |- checkAllBalances.js
     |   |- genesis-block.json
     |   '- Greeter.sol
     '- [target]
         |- Greeter.abi
         |- Greeter.bin
         |- Mortal.abi
         '- Mortal.bin
    
  5. Um diesen kompilierten Ethereum Smart Contract in die Ethereum-Blockchain zu deployen, wird eine JavaScript-Datei erstellt, welche mit den zwei folgenden Kommandos beginnt:

    var greeterFactory = eth.contract( {Inhalt der Datei target/Greeter.abi} )
    var greeterCompiled = "0x" + "{Inhalt der Datei target/Greeter.bin}"
    ...
    

    Dabei müssen die beiden Platzhalterausdrücke "{...}" durch die jeweiligen Dateinhalte ersetzt werden.

    Unter Windows erstellen Sie hierzu im src-Verzeichnis folgende drei Dateien, jeweils ohne Zeilenendezeichen am Ende:

    greeterJsTeil1.txt

    var greeterFactory = eth.contract( 
    

    greeterJsTeil2.txt

     )
    var greeterCompiled = "0x" + "
    

    greeterJsTeil3.txt

    "
    var _greeting = "Hallo Welt!"
    var Greeter = greeterFactory.new( _greeting, { from:eth.accounts[0], data:greeterCompiled, gas:47000000 }, function( e, contract ) {
       if( e ) {
          console.log( e );
       } else {
          if( !contract.address ) {
             console.log( "Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined..." );
          } else {
             console.log( "Contract mined! Address: " + contract.address );
             console.log( contract );
          }
       }
    })
    

    Anschließend führen Sie aus:

    copy /B /Y src\greeterJsTeil1.txt + target\Greeter.abi + src\greeterJsTeil2.txt + target\Greeter.bin + src\greeterJsTeil3.txt src\GreeterDeploy.js

    type src\GreeterDeploy.js

  6. Alternativ könnten Sie den obigen Solidity-Sourcecode auch in den Remix Online Solidity Compiler unter http://remix.ethereum.org kopieren, "Start to compile" und "Details" betätigen, und das JavaScript unter "WEB3DEPLOY" in die Datei "src\GreeterDeploy.js" kopieren.

  7. Die Projektstruktur sieht jetzt so aus:

    [\MeinWorkspace\EthereumDemo]
     |- priv-geth.log
     |- starte-Test-Ethereum-Blockchain.bat
     |- [Private-Blockchain]
     |   |- history
     |   |- [geth]
     |   |   '- ...
     |   '- [keystore]
     |       '- UTC--2018-01-22T09-50-58...
     |- [solc]
     |   |- msvcp140.dll
     |   |- solc.exe
     |   '- soltest.exe
     |- [src]
     |   |- checkAllBalances.js
     |   |- genesis-block.json
     |   '- Greeter.sol
     |   |- GreeterDeploy.js
     |   |- greeterJsTeil1.txt
     |   |- greeterJsTeil2.txt
     |   |- greeterJsTeil3.txt
     '- [target]
         |- Greeter.abi
         |- Greeter.bin
         |- Mortal.abi
         '- Mortal.bin
    
  8. Starten Sie die Test-Ethereum-Blockchain inklusive Mining:

    cd \MeinWorkspace\EthereumDemo

    starte-Test-Ethereum-Blockchain.bat

  9. Führen Sie in der Geth-JavaScript-Console folgende drei Kommandos aus und überprüfen Sie jeweils das Ergebnis (die beiden loadScript()-Antworttexte stammen aus dem obigen GreeterDeploy.js-JavaScript-Code, und die Greeter.greet()-Antwort stammt vom Smart Contract):

    personal.unlockAccount( web3.eth.accounts[0], "Meine Ethereum-Test-Passphrase" )

    true
    

    loadScript( 'src/GreeterDeploy.js' )

    Contract transaction send: TransactionHash: 0xe194...7dad waiting to be mined...
    true
    ...
    Contract mined! Address: 0xcd5e3f508e24fb8424ea38425f3f0c860b52372d
    

    Greeter.greet();

    "Hallo Welt!"
    

    Damit haben Sie den Ethereum Smart Contract erfolgreich ausgeführt.

  10. Da das Solidity-Skript eine kill()-Methode hat, kann es folgendermaßen aus der Blockchain entfernt werden:

    personal.unlockAccount( web3.eth.accounts[0], "Meine Ethereum-Test-Passphrase" )

    Greeter.kill.sendTransaction( { from:eth.accounts[0] } )

    Die Kontrolle erfolgt über:

    eth.getCode( Greeter.address )

    Sie erhalten:

    "0x"
    


Mini-Token-Smart-Contract: MeinToken-Demo

Diese Demo zeigt:

Führen Sie die im Folgenden beschriebenen Schritte aus.

  1. Alle oben unter Basisinstallationen: Geth, Solc, private Test-Ethereum-Blockchain beschriebenen Schritte müssen ausgeführt worden sein.

  2. Wechseln Sie in Ihr vorbereitetes EthereumDemo-Workspace-Verzeichnis (z.B. \MeinWorkspace\EthereumDemo):

    cd \MeinWorkspace\EthereumDemo

  3. Erstellen Sie im src-Unterverzeichnis das Solidity-Skript:
    MeinToken.sol

    pragma solidity ^0.4.19;
    
    contract MeinToken {
       /* Map mit Account-Adressen und dazugehoerenden Kontostaenden */
       mapping( address => uint256 ) public balanceOf;
    
       /* Konstruktor, wird bei der Initialisierung aufgerufen,
          uebertraegt initiale Menge an Tokens an den Ersteller des Smart Contracts */
       function MeinToken( uint256 initialSupply ) public {
          balanceOf[msg.sender] = initialSupply;
       }
    
       /* Transferiere Tokens */
       function transfer( address _to, uint256 _value ) public {
          require( msg.sender != _to );
          require( balanceOf[msg.sender] >= _value );
          require( balanceOf[_to] + _value >= balanceOf[_to] );
          balanceOf[msg.sender] -= _value;
          balanceOf[_to] += _value;
       }
    }
    
  4. Erstellen Sie im src-Unterverzeichnis folgende drei JavaScript-Fragmente, jeweils ohne Zeilenendezeichen am Ende.

    meinTokenJsTeil1.txt

    var meinTokenFactory = eth.contract( 
    

    meinTokenJsTeil2.txt

     )
    var meinTokenCompiled = "0x" + "
    

    meinTokenJsTeil3.txt

    "
    var initialSupply = 888
    var gasOffer = eth.getBlock( "latest" ).gasLimit / 2
    var MeinToken = meinTokenFactory.new( initialSupply, { from:eth.accounts[0], data:meinTokenCompiled, gas:gasOffer }, function( e, contract ) {
       if( e ) {
          console.log( e );
       } else {
          if( !contract.address ) {
             console.log( "Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined..." );
          } else {
             console.log( "Contract mined! Address: " + contract.address );
             console.log( contract );
          }
       }
    })
    
  5. Erstellen Sie im EthereumDemo-Projektverzeichnis die Batchdatei:
    build-MeinToken.bat

    solc\solc -o target --bin --abi --overwrite src/MeinToken.sol
    dir target
    copy /B /Y src\meinTokenJsTeil1.txt + target\MeinToken.abi + src\meinTokenJsTeil2.txt + ^
                                          target\MeinToken.bin + src\meinTokenJsTeil3.txt src\MeinTokenDeploy.js
    type src\MeinTokenDeploy.js
    
  6. Führen Sie folgende Kommandos aus:

    cd \MeinWorkspace\EthereumDemo

    build-MeinToken.bat

    tree /F

  7. Die Projektstruktur sieht jetzt so aus (falls Sie auch die obige Erster Smart Contract: Hallo-Welt-Demo ausgeführt haben, haben Sie ein paar zusätzliche Dateien, die aber nicht stören):

    [\MeinWorkspace\EthereumDemo]
     |- build-MeinToken.bat
     |- priv-geth.log
     |- starte-Test-Ethereum-Blockchain.bat
     |- [Private-Blockchain]
     |   |- history
     |   |- [geth]
     |   |   '- ...
     |   '- [keystore]
     |       '- UTC--2018-01-22T09-50-58...
     |- [solc]
     |   |- msvcp140.dll
     |   |- solc.exe
     |   '- soltest.exe
     |- [src]
     |   |- checkAllBalances.js
     |   |- genesis-block.json
     |   '- MeinToken.sol
     |   |- MeinTokenDeploy.js
     |   |- meinTokenJsTeil1.txt
     |   |- meinTokenJsTeil2.txt
     |   '- meinTokenJsTeil3.txt
     '- [target]
         |- MeinToken.abi
         '- MeinToken.bin
    
  8. Starten Sie die Blockchain:

    cd \MeinWorkspace\EthereumDemo

    starte-Test-Ethereum-Blockchain.bat

  9. Führen Sie in der Geth-JavaScript-Console aus (führen Sie die einzelnen JavaScript-Kommandos nicht zu schnell hintereinander aus):

    // Der erste Account muss über Ether verfügen (eventuell muss auf das Minig gewartet werden):

    loadScript( 'src/checkAllBalances.js' )

    // Weiteren Account anlegen (es werden mindestens zwei Accounts benötigt):

    personal.newAccount( "Meine Ethereum-Test-Passphrase" )

    web3.eth.accounts

    // Smart Contract deployen:

    personal.unlockAccount( web3.eth.accounts[0], "Meine Ethereum-Test-Passphrase" )

    loadScript( 'src/MeinTokenDeploy.js' )

    // Warten bis "Contract mined!" erscheint.

    // Default-Account definieren und entsperren:

    web3.eth.defaultAccount = web3.eth.accounts[0]

    personal.unlockAccount( web3.eth.defaultAccount, "Meine Ethereum-Test-Passphrase" )

    // Kontostände des neuen Tokens überprüfen (zu Beginn: 888 / 0, siehe: MeinTokenDeploy.js):

    MeinToken.balanceOf( web3.eth.accounts[0] )

    MeinToken.balanceOf( web3.eth.accounts[1] )

    // Token-Transfer ausführen (188 Tokens transferieren):

    MeinToken.transfer( web3.eth.accounts[1], 188 );

    // Ca. 30 Sekunden auf das Mining warten.

    // Geänderte Kontostände überprüfen (700 / 188):

    MeinToken.balanceOf( web3.eth.accounts[0] )

    MeinToken.balanceOf( web3.eth.accounts[1] )

    Sie erhalten:

    ...
    > MeinToken.transfer( web3.eth.accounts[1], 188 );
    "0xc99b4ebfc87e24c6e77462f8ddf360ab716da385d114b83304479514e19e0f41"
    >
    > MeinToken.balanceOf( web3.eth.accounts[0] )
    700
    > MeinToken.balanceOf( web3.eth.accounts[1] )
    188
    

    Sie haben erfolgreich einen Smart Contract mit eigenen Tokens implementiert und Tokens von einem Account zu einem anderen transferiert.

  10. Führen Sie in der Geth-JavaScript-Console aus:

    MeinToken.address

    Diese 40-stellige Hexadresse müssen Sie sich für die weiter unten folgenden Demos merken. Speichern Sie die Adresse in die Datei MeinToken.address.priv.txt.

  11. Dieser kleinen Mini-Token-Demo fehlt natürlich noch viel Funktionalität für einen richtigen Token. Sehen Sie sich hierzu das ERC20-Token-Beispiel an.



Remix Online Solidity Compiler als grafische Entwicklungsumgebung (GUI-IDE)

Diese Demo zeigt:

Sehen Sie sich die Doku zur Remix - Solidity IDE und das Remix-Wiki an.
Im Folgenden wird die Implementierung und Benutzung des obigen Mini-Token-Demo-Smart-Contracts demonstriert.

  1. Ihre eigene lokale Test-Ethereum-Blockchain muss installiert sein, möglichst so ähnlich wie oben unter Basisinstallationen: Geth, Solc, private Test-Ethereum-Blockchain beschrieben.

  2. Starten Sie die Test-Ethereum-Blockchain inklusive Mining:

    cd \MeinWorkspace\EthereumDemo

    starte-Test-Ethereum-Blockchain.bat

  3. Öffnen Sie die Webseite vom Remix Online Solidity Compiler: http://remix.ethereum.org.

  4. Starten Sie ein neues Projekt, indem Sie auf der Webseite oben links auf das kleine Pluszeichen klicken.
    Geben Sie bei "File Name" ein: MeinToken.sol

  5. In dem oberen mittleren leeren Fenster mit dem Titel "browser/MeinToken.sol" fügen Sie den Solidity-Skript-Sourcecode von MeinToken.sol ein.

  6. Klicken Sie im rechten Drittel oben auf den Tabulatorreiter "Compile" und dann auf den Button "Start to compile".

  7. Klicken Sie auf die Schaltfläche "Details", um die Kompilierergebnisse anzuzeigen. Unter "WEB3DEPLOY" finden Sie ein fertiges JavaScript-Programm zum Deployen des MeinToken-Smart-Contracts.
    Dieses JavaScript könnten Sie so wie oben gezeigt mit dem Kommandozeilen-Tool Geth in der Geth-JavaScript-Console ausführen. In dieser Demo soll jedoch stattdessen alles über die grafische Entwicklungsumgebung ausgeführt werden.

  8. Verbinden Sie den Remix Online Solidity Compiler mit Ihrer eigenen lokalen Test-Ethereum-Blockchain:
    Klicken Sie im rechten Drittel oben auf den Tabulatorreiter "Run", wählen Sie bei Environment "Web3 Provider", bestätigen Sie "Are you sure you want to connect to an ethereum node?" sowie "Web3 Provider Endpoint" "http://localhost:8545".

  9. Testen Sie die Verbindung:
    Geben Sie im unteren mittleren Fenster ganz unten neben dem ">"-Zeichen ein:
        web3.eth.accounts
    Sie erhalten die Adressen Ihrer Accounts, beispielsweise:

    > web3.eth.accounts
    [
      "0x4597a26af9991b297b5ccc2a8c0966e9a1a17035",
      "0x63d7d5b64dc9cc0744dedf87971f8b0777d7e226"
    ]
    
  10. Deployen Sie Ihren MeinToken-Smart-Contract in die lokale Blockchain:
    Geben Sie im unteren mittleren Fenster ganz unten neben dem ">"-Zeichen ein:
        web3.personal.unlockAccount( web3.eth.accounts[0], "Meine Ethereum-Test-Passphrase" )
    Geben Sie anschließend im mittleren Teil des rechten Fensters bei "uint256 initialSupply" einen anfänglichen Token-Betrag ein, beispielsweise 888, und betätigen Sie daneben den "Create"-Button. Sie erhalten beispielsweise:

    > web3.personal.unlockAccount( web3.eth.accounts[0], "Meine Ethereum-Test-Passphrase" )
    true
    creation of MeinToken pending...
    [block:2532 txIndex:0] from:0x459...17035, to:MeinToken.(constructor), value:0 wei, 0 logs, data:0x606...00378, hash:0xc25...c86b1
    

    Der MeinToken-Smart-Contract ist erfolgreich in die lokale Blockchain deployt.

  11. Fragen Sie zu Ihren ersten beiden mit web3.eth.accounts ermittelten Account-Adressen den Token-Kontostand ab:
    Geben Sie im rechten Drittel neben dem "balanceOf"-Button bei "address" nacheinander die beiden Account-Adressen ein und betätigen Sie jeweils den "balanceOf"-Button. Achten Sie dabei darauf, dass Sie die Hex-Adressen mit vorangestelltem "0x" sowie eingeschlossen in Anführungszeichen eingeben, bespielsweise so:
        "0x4597a26af9991b297b5ccc2a8c0966e9a1a17035"
    Sie erhalten 888 und 0.

  12. Führen Sie mit dem MeinToken-Smart-Contract einen Transfer von Tokens aus:
    Geben Sie im unteren mittleren Fenster ganz unten neben dem ">"-Zeichen ein:
        web3.personal.unlockAccount( web3.eth.accounts[0], "Meine Ethereum-Test-Passphrase" )
    Geben Sie anschließend im rechten Drittel neben dem "transfer"-Button bei "address _to, uint256 _value" die zweite Account-Adresse (wieder inklusive Anführungszeichen) und einen Betrag ein, beispielsweise so:
        "0x63d7d5b64dc9cc0744dedf87971f8b0777d7e226", 111
    Betätigen Sie den "transfer"-Button und warten Sie etwas auf das Mining.

  13. Überprüfen Sie wieder über den "balanceOf"-Button die Token-Kontostände der beiden Accounts:
    Sie erhalten 777 und 111.

    Es wurden erfolgreich Tokens im MeinToken-Smart-Contract zwischen Accounts transferiert.



Einen MeinToken-Transfer mit dem GUI-Tool Mist ausführen

Diese Demo zeigt:

Informationen zum Ethereum-Client Mist finden Sie beispielsweise unter: Ethereum Mist Wiki bei GitHub, Ethereum Mist bei GitHub, Using Mist Ethereum Wallet, Getting Started with Ethereum Mist Wallet.

Führen Sie die im Folgenden beschriebenen Schritte aus.

  1. Falls Sie Mist noch nicht installiert haben:
    Downloaden Sie von Ethereum Wallet and Mist Cliente Ligero (GitHub) die für Ihr Betriebssystem geeignete Installationsdatei, beispielsweise für Windows: Mist-installer-0-9-3.exe. Führen Sie die Installationsdatei aus.

  2. Alle oben unter Mini-Token-Smart-Contract: MeinToken-Demo beschriebenen Schritte müssen ausgeführt worden sein, Ihre Ethereum-Blockchain muss aktiv sein, und der MeinToken-Smart-Contract muss deployt sein.

  3. Falls noch nicht geschehen, starten Sie die Test-Ethereum-Blockchain:

    cd \MeinWorkspace\EthereumDemo

    starte-Test-Ethereum-Blockchain.bat

  4. Führen Sie in der Geth-JavaScript-Console aus:

    web3.eth.accounts

    Sie erhalten die Hex-Adressen der beiden Accounts. Diese Adressen benötigen Sie weiter unten.

  5. Starten Sie Mist. Stellen Sie sicher, dass sich Mist mit Ihrer eigenen Test-Ethereum-Blockchain verbunden hat.

  6. Klicken Sie oben links auf "Wallets".
    Rechts oben wird der standig steigende Kontostand in Ether angezeigt.
    Weiter unten finden Sie unter "Konten Übersicht" die beiden von Ihnen eingerichteten Accounts. Wenn Sie auf einen einzelnen Account klicken, wird die jeweilige 40-stellige Account-Adresse angezeigt.
    Unter "Konto hinzufügen" könnten Sie weitere Accounts einrichten.

  7. Klicken Sie oben rechts auf "Verträge".
    Unter "Neue Verträge veröffentlichen" könnten Sie einen weiteren Smart Contract erstellen und deployen.
    Um den bereits deployten Smart Contract zu verwenden, klicken Sie unter "Eigene Verträge" auf "Verträge beobachten". Es erscheint ein Eingabedialog. Geben Sie ein:
    - Vertragsadresse: Die in der Datei "MeinToken.address.priv.txt" gespeicherte Adresse des Smart Contracts,
    - Vertragsname: MeinToken,
    - JSON-Schnittstelle: Der Inhalt der Datei "EthereumDemo\target\MeinToken.abi".

  8. Unter "Eigene Verträge" wird Ihr Smart Contract "MeinToken" angezeigt.

    Unter "Vertrag auslesen" / "Balance of" können Sie die Kontostände des implementierten Tokens abfragen: Geben Sie eine der beiden Account-Adressen ein: Sie erhalten den letzten Kontostand, also 700 bzw. 188 Tokens.

    Unter "In Vertrag schreiben" wählen Sie bei "Select function" die Methode "Transfer". Dabei erscheinen zwei Eingabefelder für die beiden Parameter der Transfer-Methode:
    - to address: Hier tragen Sie die Account-Adresse des zweiten Accounts ein,
    - value: Hier tragen Sie die Anzahl der zu übertragenen Tokens ein, z.B. 111.
    Klicken Sie auf "Ausführen". Es folgt ein Dialog, in dem nach dem Passwort gefragt wird: Geben Sie "Meine Ethereum-Test-Passphrase" ein, und betätigen Sie "Send Transaction".
    Erfragen Sie erneut unter "Vertrag auslesen" / "Balance of" die beiden Token-Kontostände: Sie erhalten die geänderten Werte 589 und 299.

    Die Smart-Contract-Transaktion wurde erfolgreich ausgeführt.




DApp-Webseite für den Smart Contract mit Node.js

Diese Demo zeigt:

Verwendet werden folgende Versionen:

Sehen Sie sich die Doku zu git, npm, Node.js und web3.js an.

Falls Sie neuere als die oben genannten Versionen verwenden, erhalten Sie eventuell Fehlermeldungen wegen fehlender web3.min.js. Beachten Sie in diesem Fall die Webseite: web3.min.js is missing.

Führen Sie die im Folgenden beschriebenen Schritte aus.

  1. Alle oben unter Mini-Token-Smart-Contract: MeinToken-Demo beschriebenen Schritte müssen ausgeführt worden sein.

  2. Wechseln Sie in Ihr Workspace-Verzeichnis (z.B. \MeinWorkspace) und legen Sie parallel zum EthereumDemo-Projektverzeichnis ein neues Projektverzeichnis an:

    cd \MeinWorkspace

    mkdir EthNodejsDApp

    cd EthNodejsDApp

  3. Sie benötigen eine möglichst aktuelle Version von Git. Falls Sie kein Git installiert haben, oder falls Ihre Git-Version nicht aktuell genug ist, downloaden Sie von https://git-scm.com/download/ die für Ihr Betriebssystem geeignete Installationsdatei, beispielsweise für Windows Git-2.16.1-64-bit.exe, und führen Sie damit die Installation von Git durch. Kontrollieren Sie die Installation mit:

    git --version

    git --help

  4. Sie benötigen eine aktuelle Version von Node.js. Downloaden Sie von https://nodejs.org die für Ihr Betriebssystem geeignete Installationsdatei, beispielsweise für Windows node-v9.6.1-x64.msi, und führen Sie damit die Installation von Node.js durch. Kontrollieren Sie die Installation mit:

    node -v

    node -h

    npm -v

    npm -h

  5. Wechseln Sie in Ihr neues EthNodejsDApp-Projektverzeichnis und initiieren Sie ein Node.js-Projekt:

    cd \MeinWorkspace\EthNodejsDApp

    npm install web3@0.20.4

    npm install ethereum/web3.js

    npm init

    npm list

    type package.json

    dir node_modules\web3\dist\web3.min.js

  6. Erstellen Sie im EthNodejsDApp-Projektverzeichnis die DApp-HTML-Datei:
    MeinTokenDAppWebseite.html

    <html>
    <head>
       <title>MeinToken-Smart-Contract-DApp</title>
       <meta http-equiv="content-type" content="text/html;charset=utf-8">
       <style>* { font-family: sans-serif; }</style>
       <script type="text/javascript" src="./node_modules/web3/dist/web3.min.js"></script>
       <script type="text/javascript">
    
          // Hier die Adresse des deployten MeinToken-Smart-Contracts eintragen:
          const contractAddress = "0xf07a9248ac043cf039a6f76113b78f89d483b2c8";
          // Hier den Inhalt der Datei target\MeinToken.abi eintragen:
          const abi = '[{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf",\
                         "outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},\
                        {"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],\
                         "name":"transfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},\
                        {"inputs":[{"name":"initialSupply","type":"uint256"}],"payable":false,"stateMutability":"nonpayable",\
                         "type":"constructor"}]';
    
          const Web3 = require( 'web3' );
          const web3 = new Web3( new Web3.providers.HttpProvider( 'http://localhost:8545' ) );
          const meinTokenContract = web3.eth.contract( JSON.parse( abi ) );
          const meinTokenContractInstance = meinTokenContract.at( contractAddress );
          const account0 = web3.eth.accounts[0];
          const account1 = web3.eth.accounts[1];
          web3.eth.defaultAccount = web3.eth.accounts[0];
    
          function meinTokenGetBalanceOf() {
             try {
                var balanceOf0 = meinTokenContractInstance.balanceOf( account0 );
                var balanceOf1 = meinTokenContractInstance.balanceOf( account1 );
                document.getElementById('account0').innerText = "Account 0 (" + account0 + "): balanceOf: " + balanceOf0;
                document.getElementById('account1').innerText = "Account 1 (" + account1 + "): balanceOf: " + balanceOf1;
             } catch( e ) {
                document.write( "<br/><b>Error: " + e.message + "</b>" );
             }
          }
          function meinTokenTransfer() {
             var betrag     = document.MeinFormular.betrag.value;
             var passphrase = document.MeinFormular.passphrase.value;
             if( null == betrag     || "" == betrag     ) { alert( "Betrag fehlt!"     ); return false; }
             if( null == passphrase || "" == passphrase ) { alert( "Passphrase fehlt!" ); return false; }
             var message = "Transfer startet mit Betrag " + betrag + ".";
             document.getElementById('message').innerText = message;
             try {
                if( passphrase != "-" ) { web3.personal.unlockAccount( account0, passphrase ); }
                meinTokenContractInstance.transfer( account1, betrag );
                if( passphrase != "-" ) { web3.personal.lockAccount( account0 ); }
                message += "\nCirca 30 Sekunden auf das Mining warten, und dann mit F5 refreshen."
                document.getElementById('message').innerText = message;
                alert( message );
             } catch( e ) {
                document.write( "<br/><b>Error: " + e.message + "</b>" );
             }
          }
       </script>
    </head>
    
    <body bgcolor="#EEFFEE" onload="meinTokenGetBalanceOf()">
       <h1>DApp-Webseite zum MeinToken-Smart-Contract</h1>
       <div id="account0"></div>
       <div id="account1"></div> <br/>
       <form name="MeinFormular" method="post" onSubmit="meinTokenTransfer()">
          Betrag:     <input type="text" name="betrag"     size="10" maxlength="10">
          Passphrase: <input type="text" name="passphrase" size="45" maxlength="42">
          <input type="submit" value="starte Transfer">
       </form>
       <div id="message"></div>
    </body>
    </html>
    

    Bei "const contractAddress = ..." müssen Sie die in der Datei "MeinToken.address.priv.txt" gespeicherte Adresse des MeinToken-Smart-Contracts eintragen.

  7. Die Projektstruktur sieht jetzt so aus:

    [\MeinWorkspace]
     |- [EthereumDemo]
     |   '- ...
     '- [EthNodejsDApp]
         |- MeinTokenDAppWebseite.html
         |- package-lock.json
         |- package.json
         '- [node_modules]
             '- ...
    
  8. Falls noch nicht geschehen, starten Sie die Test-Ethereum-Blockchain:

    cd \MeinWorkspace\EthereumDemo

    starte-Test-Ethereum-Blockchain.bat

  9. Öffnen Sie die DApp-Webseite:

    cd \MeinWorkspace\EthNodejsDApp

    start MeinTokenDAppWebseite.html

    Sie erhalten beispielsweise:

  10. Merken Sie sich die jetzigen Kontostände, geben Sie einen Betrag an zu transferierenden Tokens und die Passphrase "Meine Ethereum-Test-Passphrase" ein, und betätigen Sie den "starte Transfer"-Button. Warten Sie ausreichend lange, damit die Transaktion per Mining der Blockchain hinzugefügt wird. Anschließend refreshen Sie die Webseite, in den meisten Webbrowsern mit F5 oder mit Strg+R. Sie sehen die um den eingegebenen Betrag geänderten Kontostände.



Transfer von Ether mit Web3j und Java

Diese Demo zeigt:

Verwendet werden folgende Versionen:

Sehen Sie sich an: Java, JDK 9, Maven, Web3j-Projekt, Web3j-Doku, Web3j-Doku.

Führen Sie die im Folgenden beschriebenen Schritte aus.

  1. Ein aktuelles JDK 9 und ein aktuelles Maven müssen installiert sein.

  2. Eine Java-IDE wie beispielsweise JetBrains IntelliJ IDEA oder Eclipse ist nicht zwingend notwendig, aber vereinfacht den Entwicklungsprozess enorm.

  3. Wechseln Sie in Ihr Workspace-Verzeichnis (z.B. \MeinWorkspace) und führen Sie folgende Kommandos aus:

    cd \MeinWorkspace

    mkdir EthJavaDApp

    cd EthJavaDApp

    md src\main\java\de\meinefirma\meinprojekt

    tree /F

  4. Erstellen Sie im EthJavaDApp-Projektverzeichnis die Maven-Konfigurationsddatei:
    pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>de.meinefirma.meinprojekt</groupId>
      <artifactId>EthJavaDApp</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>jar</packaging>
      <name>EthJavaDApp</name>
      <properties>
        <project.build.sourceEncoding>ISO-8859-1</project.build.sourceEncoding>
      </properties>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.7.0</version>
            <configuration>
              <source>1.8</source>
              <target>1.8</target>
            </configuration>
          </plugin>
        </plugins>
      </build>
      <dependencies>
        <dependency>
          <groupId>org.web3j</groupId>
          <artifactId>core</artifactId>
          <version>3.3.1</version>
        </dependency>
      </dependencies>
    </project>
    
  5. Erstellen Sie im src\main\java\de\meinefirma\meinprojekt-Unterverzeichnis die Java-Klasse:
    EtherTransfer.java

    package de.meinefirma.meinprojekt;
    
    import org.web3j.protocol.Web3j;
    import org.web3j.protocol.admin.Admin;
    import org.web3j.protocol.admin.methods.response.PersonalUnlockAccount;
    import org.web3j.protocol.core.DefaultBlockParameterName;
    import org.web3j.protocol.core.methods.request.Transaction;
    import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
    import org.web3j.protocol.core.methods.response.EthSendTransaction;
    import org.web3j.protocol.core.methods.response.TransactionReceipt;
    import org.web3j.protocol.http.HttpService;
    import org.web3j.tx.Contract;
    import org.web3j.tx.ManagedTransaction;
    import org.web3j.utils.Convert;
    import java.math.BigInteger;
    import java.util.Optional;
    
    public class EtherTransfer
    {
       public static void main( String[] args ) throws Exception
       {
          // Programm so erweitern, dass Parameter ausgelesen oder uebergeben werden:
          transferiereEther( "http://localhost:8545",
                // Hier die Adressen der beiden Accounts eintragen (Ergebnis von: web3.eth.accounts):
                "0x4597a26af9991b297b5ccc2a8c0966e9a1a17035",
                "0x63d7d5b64dc9cc0744dedf87971f8b0777d7e226",
                // Hier den zu transferierenden Betrag und die Passphrase eintragen:
                "10", "Meine Ethereum-Test-Passphrase" );
       }
    
       public static void transferiereEther(
             String ethereumUrl, String senderAdresse, String empfaengerAdresse, String betragEther, String passphrase )
             throws Exception
       {
          Admin admin = Admin.build( new HttpService( ethereumUrl ) );
          PersonalUnlockAccount personalUnlockAccount = admin.personalUnlockAccount( senderAdresse, passphrase ).send();
          if( !personalUnlockAccount.accountUnlocked() ) {
             System.out.println( "\nFehler: Account-Unlock fehlgeschlagen." );
             return;
          }
          Web3j web3j = Web3j.build( new HttpService( ethereumUrl ) );
          EthGetTransactionCount txCount = web3j.ethGetTransactionCount(
                senderAdresse, DefaultBlockParameterName.LATEST ).sendAsync().get();
          BigInteger nonce = txCount.getTransactionCount();
          BigInteger betrag = Convert.toWei( betragEther, Convert.Unit.ETHER ).toBigInteger();
          Transaction transaction = Transaction.createEtherTransaction(
                senderAdresse, nonce, ManagedTransaction.GAS_PRICE, Contract.GAS_LIMIT, empfaengerAdresse, betrag );
          EthSendTransaction response = web3j.ethSendTransaction( transaction ).sendAsync().get();
          if( response.hasError() ) {
             System.out.println( "\nFehler: " + response.getError().getMessage() );
             return;
          }
          String txHash = response.getTransactionHash();
          System.out.print( "\nTxHash: " + txHash + "\nWarten auf das Mining " );
          for( int i = 0; i < 600; i++ ) {
             Optional<TransactionReceipt> transactionReceipt =
                   web3j.ethGetTransactionReceipt( txHash ).send().getTransactionReceipt();
             if( transactionReceipt.isPresent() ) {
                System.out.println( "\nTransfer von " + betragEther + " Ether abgeschlossen, benutzte Gas-Menge: " +
                                    transactionReceipt.get().getGasUsed() );
                return;
             }
             System.out.print( "." );
             Thread.sleep( 1000 );
          }
          System.out.println( "\nDer Transfer konnte innerhalb von 10 Minuten nicht abgeschlossen werden. Ist Mining aktiv?" );
       }
    }
    

    Ersetzen Sie in der main()-Methode die Adressen der beiden Accounts durch Ihre.

  6. Kompilieren Sie EtherTransfer.java:

    cd \MeinWorkspace\EthJavaDApp

    mvn clean package

    Das Java-Programm ist kompilierbar, und Web3j wurde erfolgreich eingebunden.

  7. Die Projektstruktur sieht jetzt so aus:

    [\MeinWorkspace\EthJavaDApp]
     |- pom.xml
     |- [src]
     |   '- [main]
     |       '- [java]
     |           '- [de]
     |               '- [meinefirma]
     |                   '- [meinprojekt]
     |                       '- EtherTransfer.java
     '- [target]
         |- EthJavaDApp-1.0-SNAPSHOT.jar
         '- ...
    
  8. Alle oben unter Basisinstallationen: Geth, Solc, private Test-Ethereum-Blockchain beschriebenen Schritte müssen ausgeführt worden sein.

  9. Starten Sie die Test-Ethereum-Blockchain:

    cd \MeinWorkspace\EthereumDemo

    starte-Test-Ethereum-Blockchain.bat

    Fragen Sie in der Geth-JavaScript-Console die Accounts und Ether-Kontostände ab:

    loadScript( 'src/checkAllBalances.js' )

    Es müssen mindestens zwei Accounts existieren. Falls es nur einen gibt, legen Sie einen weiteren an, wie oben beschrieben.

  10. Jetzt gibt es drei Möglichkeiten:

  11. Führen Sie das EtherTransfer-Programm aus.
    Sie erhalten beispielsweise:

    TxHash: 0xdc96314d6443c81d86c7a4afc6413b2b4127fee739b9bb7ae607ef7267bad417
    Warten auf das Mining ........................................
    Transfer von 10 Ether abgeschlossen, benutzte Gas-Menge: 21000
    

    Überprüfen Sie mit Ihrer Wallet-Anwendung oder in der Geth-JavaScript-Console mit loadScript( 'src/checkAllBalances.js' ) die Ether-Kontostände.

    Es wurden erfolgreich 10 Ether von einem Account zu einem anderen transferiert.



Transfer von eigenen Smart-Contract-Tokens mit Web3j und Java

Diese Demo zeigt:

Als Smart Contract wird der oben gezeigte MeinToken-Smart-Contract verwendet.

Führen Sie die im Folgenden beschriebenen Schritte aus.

  1. Sowohl alle oben unter MeinToken-Smart-Contract als auch alle unter Transfer von Ether mit Web3j und Java beschriebenen Schritte müssen ausgeführt worden sein.

  2. Um die Java-Schnittstellenklasse zur Interaktion mit dem Smart Contract zu erstellen, wird das Web3j-Kommandozeilen-Tool benötigt. Downloaden Sie web3j-3.3.1.zip von https://github.com/web3j/web3j/releases. Entzippen Sie diese Datei in das Unterverzeichnis web3j-3.3.1 in Ihrem EthJavaDApp-Projektverzeichnis. Überprüfen Sie die Installation mit:

    cd \MeinWorkspace\EthJavaDApp

    web3j-3.3.1\bin\web3j.bat version

    web3j-3.3.1\bin\web3j.bat solidity

  3. Die folgenden Kommandos gehen davon aus, dass der MeinToken-Smart-Contract im Projektverzeichnis \MeinWorkspace\EthereumDemo parallel zum aktuellen Projektverzeichnis \MeinWorkspace\EthJavaDApp angelegt wurde. Falls das bei Ihnen anders ist, müssen Sie die Pfade anpassen. Führen Sie aus:

    cd \MeinWorkspace\EthJavaDApp

    web3j-3.3.1\bin\web3j.bat solidity generate ..\EthereumDemo\target\MeinToken.bin ..\EthereumDemo\target\MeinToken.abi -o src\main\java -p de.meinefirma.meinprojekt

    dir src\main\java\de\meinefirma\meinprojekt

    Es wurde die neue Java-Klasse MeinToken.java generiert.

  4. Erstellen Sie im src\main\java\de\meinefirma\meinprojekt-Unterverzeichnis die Java-Klasse:
    MeinTokenTransfer.java

    package de.meinefirma.meinprojekt;
    
    import org.web3j.crypto.CipherException;
    import org.web3j.crypto.Credentials;
    import org.web3j.crypto.WalletUtils;
    import org.web3j.protocol.Web3j;
    import org.web3j.protocol.core.RemoteCall;
    import org.web3j.protocol.core.methods.response.TransactionReceipt;
    import org.web3j.protocol.http.HttpService;
    import org.web3j.tx.Contract;
    import org.web3j.tx.ManagedTransaction;
    import java.io.*;
    import java.math.BigInteger;
    import java.util.*;
    import java.util.concurrent.CompletableFuture;
    
    public class MeinTokenTransfer
    {
       // Hier die Adresse des MeinToken-Smart-Contracts in der Blockchain
       // und entweder die Passphrase oder den Private Key eintragen:
       public static final String DEFAULT_CONTRACT_ADRESSE      = "0xf07a9248ac043cf039a6f76113b78f89d483b2c8";
       public static final String DEFAULT_PASSPHRASE_OR_PRIVKEY = "Meine Ethereum-Test-Passphrase";
       public static final String DEFAULT_ETHEREUM_URL          = "http://localhost:8545";
       public static final List<String> DEFAULT_KEYSTORE_DIRS   = Arrays.asList(
             "../EthereumDemo/Private-Blockchain/keystore",
             "../EthereumDemo/Rinkeby-Blockchain/keystore" );
    
       public static void main( String[] args ) throws Exception
       {
          if( args.length < 1 ) {
             System.out.println( "\nFolgende Parameter koennen uebergeben werden:\n" +
                   "   Anzahl zu transferierender Tokens\n" +
                   "   Passphrase oder Private Key\n" +
                   "   Sender-Account-Adresse\n" +
                   "   Empfaenger-Account-Adresse\n" +
                   "   MeinToken-Contract-Adresse\n" +
                   "   Keystore-Verzeichnis\n" +
                   "   Ethereum-Blockchain-URL\n" );
          }
          String betragStr    = ( args.length > 0 ) ? args[0] : "0";
          String pssPhrOrPrvK = ( args.length > 1 ) ? args[1] : DEFAULT_PASSPHRASE_OR_PRIVKEY;
          String contractAdr  = ( args.length > 4 ) ? args[4] : DEFAULT_CONTRACT_ADRESSE;
          String keystoreDir  = ( args.length > 5 ) ? args[5] : "";
          String ethereumUrl  = ( args.length > 6 ) ? args[6] : DEFAULT_ETHEREUM_URL;
    
          List<String> accounts = ermittleAccounts( ethereumUrl );
          String senderAdresse     = ( args.length > 2 ) ? args[2] : accounts.get( 0 );
          String empfaengerAdresse = ( args.length > 3 ) ? args[3] : accounts.get( 1 );
          System.out.println( "Accounts:     " + accounts );
    
          List<String> keystoreDirs = new ArrayList<>();
          keystoreDirs.add( keystoreDir );
          keystoreDirs.addAll( DEFAULT_KEYSTORE_DIRS );
    
          MeinToken meinToken = null;
          List<BigInteger> kontostaende = null;
          try {
             meinToken = initMeinToken( ethereumUrl, contractAdr, senderAdresse, pssPhrOrPrvK, keystoreDirs );
             kontostaende = liesKontostaende( meinToken, senderAdresse, empfaengerAdresse );
             System.out.println( "Kontostaende: " + kontostaende.get( 0 ) + " / " + kontostaende.get( 1 ) );
          } catch( Exception ex ) {
             System.out.println( "Fehler bei der Abfrage des MeinToken Smart Contracts. " +
                                 "Sind Contract-Adresse sowie Passphrase bzw. Private Key korrekt?" );
             ex.printStackTrace();
             return;
          }
    
          long betrag = Long.parseLong( betragStr );
          if( betrag > 0 ) {
             System.out.println( betrag + " Tokens werden transferiert, ca. 30 Sekunden auf das Mining warten ..." );
             kontostaende = transferiereTokens( meinToken, senderAdresse, empfaengerAdresse, betrag, 180 );
             System.out.println( "Kontostaende: " + kontostaende.get( 0 ) + " / " + kontostaende.get( 1 ) );
          }
       }
    
       public static List<String> ermittleAccounts( String ethereumUrl ) throws IOException
       {
          Web3j web3j = Web3j.build( new HttpService( ethereumUrl ) );
          return web3j.ethAccounts().send().getAccounts();
       }
    
       public static MeinToken initMeinToken( String ethereumUrl, String meinTokenContractAdresse,
                                              String account, String passphraseOrPrivateKey, List<String> keystoreDirs )
       {
          Web3j web3j = Web3j.build( new HttpService( ethereumUrl ) );
          Credentials credentials = null;
          try {
             credentials = getCredentialsFromKeystore( account, passphraseOrPrivateKey, keystoreDirs );
          } catch( Exception ex1 ) {
             try {
                credentials = Credentials.create( passphraseOrPrivateKey );
             } catch( Exception ex2 ) {
                throw new RuntimeException( ex1 );
             }
          }
          return MeinToken.load(
                meinTokenContractAdresse, web3j, credentials, ManagedTransaction.GAS_PRICE, Contract.GAS_LIMIT );
       }
    
       public static List<BigInteger> liesKontostaende(
             MeinToken meinToken, String senderAdresse, String empfaengerAdresse ) throws Exception
       {
          List<BigInteger> kontostaende = new ArrayList<>();
          kontostaende.add( meinToken.balanceOf( senderAdresse     ).send() );
          kontostaende.add( meinToken.balanceOf( empfaengerAdresse ).send() );
          return kontostaende;
       }
    
       public static List<BigInteger> transferiereTokens(
             MeinToken meinToken, String senderAdresse, String empfaengerAdresse, long betrag, int timeoutSek )
             throws Exception
       {
          if( betrag > 0 ) {
             RemoteCall<TransactionReceipt> rc = meinToken.transfer( empfaengerAdresse, BigInteger.valueOf( betrag ) );
             CompletableFuture<TransactionReceipt> txFuture = rc.sendAsync();
             for( int i = 0; i < timeoutSek; i++ ) {
                if( txFuture.isDone() ) { break; }
                System.out.print( "." );
                Thread.sleep( 1000 );
             }
             if( timeoutSek > 0 ) { System.out.println( "" ); }
             if( txFuture.isCompletedExceptionally() || txFuture.isCancelled() ) {
                throw new Exception( "MeinToken-Transfer fehlgeschlagen: " + txFuture.get().getStatus() );
             }
             if( !txFuture.isDone() && timeoutSek > 0 ) {
                throw new Exception( "Der MeinToken-Transfer konnte nicht innerhalb von " + timeoutSek +
                                     " Sekunden abgeschlossen werden. Ist Mining aktiv?" );
             }
             if( txFuture.isDone() ) {
                TransactionReceipt txReceipt = txFuture.get();
                System.out.println( "MeinToken-Transfer erfolgreich, GasUsed: " + txReceipt.getGasUsed() +
                      ", BlockNumber: " + txReceipt.getBlockNumber() + ", TxHash: " + txReceipt.getTransactionHash() );
             }
          }
          return liesKontostaende( meinToken, senderAdresse, empfaengerAdresse );
       }
    
       private static Credentials getCredentialsFromKeystore( String account, String passphrase, List<String> keystoreDirs )
             throws IOException, CipherException
       {
          File[] ksDateien = null;
          for( String ksDir : keystoreDirs ) {
             ksDateien = new File( ksDir ).listFiles( f -> f.isFile() && f.getName().contains( account.substring( 2 ) ) );
             if( ksDateien != null && ksDateien.length != 0 ) {
                break;
             }
          }
          if( ksDateien == null || ksDateien.length == 0 ) {
             throw new IOException(
                   "Fehler: Keine zum Account " + account + " passende Keystore-Datei in den Keystore-Verzeichnissen " +
                         keystoreDirs + " gefunden." );
          }
          return WalletUtils.loadCredentials( passphrase, ksDateien[0] );
       }
    }
    

    Tragen Sie bei DEFAULT_PASSPHRASE_OR_PRIVKEY und keystoreDirs die Werte aus Ihrer Blockchain ein, und bei DEFAULT_CONTRACT_ADRESSE die in MeinToken.address.priv.txt gespeicherte Smart-Contract-Adresse.

  5. Die beiden Projektstrukturen sehen jetzt so aus:

    [\MeinWorkspace\EthereumDemo]
     |- build-MeinToken.bat
     |- MeinToken.address.priv.txt
     |- priv-geth.log
     |- starte-Test-Ethereum-Blockchain.bat
     |- [Private-Blockchain]
     |   |- history
     |   |- [geth]
     |   |   '- ...
     |   '- [keystore]
     |       |- UTC--2018-01-26T18-36-00...
     |       '- UTC--2018-01-26T18-37-34...
     |- [solc]
     |   '- ...
     |- [src]
     |   '- ...
     '- [target]
         |- MeinToken.abi
         '- MeinToken.bin
    
    [\MeinWorkspace\EthJavaDApp]
     |- pom.xml
     |- [src]
     |   '- [main]
     |       '- [java]
     |           '- [de]
     |               '- [meinefirma]
     |                   '- [meinprojekt]
     |                       |- EtherTransfer.java
     |                       |- MeinToken.java
     |                       '- MeinTokenTransfer.java
     |- [target]
     |   '- ...
     '- [web3j-3.3.1]
         |- [bin]
         |   '- web3j
         |   '- web3j.bat
         '- [lib]
             '- ...
    
  6. Kompilieren Sie die Java-Klassen:

    cd \MeinWorkspace\EthJavaDApp

    mvn clean package

  7. Um die MeinTokenTransfer-Java-Klasse auszuführen, gibt es wieder die drei oben genannten Möglichkeiten.

  8. Wenn Sie MeinTokenTransfer ohne Kommandozeilenparameter ausführen, erscheint ein Text, der die möglichen Parameter nennt, sowie die beiden Account-Adressen.

    Wenn Sie MeinTokenTransfer aufrufen mit:
       0 "Meine Ethereum-Test-Passphrase"
    dann erhalten Sie die beiden Account-Adressen sowie deren MeinToken-Kontostände.

    Wenn Sie MeinTokenTransfer aufrufen mit:
       10 "Meine Ethereum-Test-Passphrase"
    dann erhalten Sie beispielsweise:

    Accounts:     [0x4597a26af9991b297b5ccc2a8c0966e9a1a17035, 0x63d7d5b64dc9cc0744dedf87971f8b0777d7e226]
    Kontostaende: 828 / 60
    10 Tokens werden transferiert, ca. 30 Sekunden auf das Mining warten ...
    ...............................
    MeinToken-Transfer erfolgreich, GasUsed: 33924, BlockNumber: 3390, TxHash: 0xae0d815da94ef13354dfc8...
    Kontostaende: 818 / 70
    

    Warten Sie eine Weile auf das Mining und fragen Sie die Kontostände erneut ab.

    Es wurden erfolgreich 10 MeinToken von einem Account zu einem anderen transferiert.

  9. Falls Sie folgende Fehlermeldung erhalten:

    org.web3j.protocol.exceptions.TransactionException: Error processing request: unknown transaction

    Dann verwenden Sie wahrscheinlich eine ungünstige Kombination von Geth und Web3j. Beispielsweise bei Kombinationen von Geth 1.8.0 bis 1.8.1 mit Web3j 3.2.0 bis 3.3.1 gibt es diesen Fehler. Siehe hierzu: Web3j Issue 318.

    Verwenden Sie Geth entweder in Version 1.7.3 oder in mindestens Version 1.8.2 um den Fehler zu vermeiden.



DApp-Webseite für den Smart Contract mit Java

Diese Demo zeigt:

Diese Demo verwendet JSP (JavaServer Pages) um das Beispiel kurz zu halten. In ernsthaften Anwendungen werden eher andere mit Java einsetzbare Web-Frameworks verwendet, wie etwa JSF, Spring MVC oder Angular.

Als Smart Contract wird wieder der oben gezeigte MeinToken-Smart-Contract verwendet.

Führen Sie die im Folgenden beschriebenen Schritte aus.

  1. Die unter Transfer von eigenen Smart-Contract-Tokens mit Web3j und Java beschriebenen Schritte müssen ausgeführt worden sein.

  2. Ersetzen Sie im EthJavaDApp-Projektverzeichnis den Inhalt der Maven-Projektkonfigurationsdatei:
    pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>de.meinefirma.meinprojekt</groupId>
      <artifactId>EthJavaDApp</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>war</packaging>
      <name>EthJavaDApp</name>
      <properties>
        <project.build.sourceEncoding>ISO-8859-1</project.build.sourceEncoding>
      </properties>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.7.0</version>
            <configuration>
              <source>1.8</source>
              <target>1.8</target>
            </configuration>
          </plugin>
          <plugin>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-maven-plugin</artifactId>
            <version>9.4.8.v20171121</version>
            <configuration>
              <webAppConfig>
                <contextPath>/${project.artifactId}</contextPath>
              </webAppConfig>
            </configuration>
          </plugin>
        </plugins>
      </build>
      <dependencies>
        <dependency>
          <groupId>org.web3j</groupId>
          <artifactId>core</artifactId>
          <version>3.3.1</version>
        </dependency>
      </dependencies>
    </project>
    
  3. Erzeugen Sie das zusätzliche Webapp-Verzeichnis:

    cd \MeinWorkspace\EthJavaDApp

    mkdir src\main\webapp\WEB-INF

  4. Erstellen Sie im src\main\webapp\WEB-INF-Verzeichnis die Webapp-Konfigurationsdatei:
    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
       <display-name>MeinToken-Smart-Contract-DApp (EthJavaDApp)</display-name>
    </web-app>
    
  5. Erstellen Sie im src\main\webapp-Verzeichnis die JSP-Datei:
    index.jsp

    <%@ page import="java.math.BigInteger" %>
    <%@ page import="java.util.*" %>
    <%@ page import="de.meinefirma.meinprojekt.*" %>
    
    <%
       String ethereumUrl  = MeinTokenTransfer.DEFAULT_ETHEREUM_URL;
       long   newTimestamp = (new Date()).getTime();
    
       List<String> accounts = MeinTokenTransfer.ermittleAccounts( ethereumUrl );
    
       String contract  = request.getParameter( "contract" );
       String account0  = request.getParameter( "account0" );
       String account1  = request.getParameter( "account1" );
       String password  = request.getParameter( "password" );
       String betrag    = request.getParameter( "betrag"   );
       String timestamp = request.getParameter( "timestamp" );
       if( contract == null || contract.isEmpty() ) { contract = MeinTokenTransfer.DEFAULT_CONTRACT_ADRESSE; }
       if( account0 == null || account0.isEmpty() ) { account0 = accounts.get( 0 ); }
       if( account1 == null || account1.isEmpty() ) { account1 = accounts.get( 1 ); }
       if( password == null || password.isEmpty() ) { password = MeinTokenTransfer.DEFAULT_PASSPHRASE_OR_PRIVKEY; }
       if( betrag   == null || betrag.isEmpty()   ) { betrag = ""; }
    
       MeinToken meinToken = null;
       List<BigInteger> kontostaende = null;
       try {
          meinToken = MeinTokenTransfer.initMeinToken(
                            ethereumUrl, contract, account0, password, MeinTokenTransfer.DEFAULT_KEYSTORE_DIRS );
          kontostaende = MeinTokenTransfer.liesKontostaende( meinToken, account0, account1 );
       } catch( Exception ex ) {
          out.println( "\n<br><font color='red'>Fehler bei der Abfrage des MeinToken Smart Contracts. " +
                             "Sind Contract-Adresse sowie Passphrase bzw. Private Key korrekt?<br>\n" +
                             ex.getMessage() + "</font><br><br>\n" );
          kontostaende = new ArrayList<BigInteger>();
          kontostaende.add( BigInteger.valueOf( -1 ) );
          kontostaende.add( BigInteger.valueOf( -1 ) );
       }
    
       if( meinToken != null && !betrag.isEmpty() && ("" + timestamp).equals( session.getAttribute( "timestamp"  ) ) ) {
          try {
             long betr = Long.parseLong( betrag );
             if( betr > 0 ) {
                System.out.println( "transferiere " + betr + " Tokens von " + account0 + " nach " + account1 );
                kontostaende = MeinTokenTransfer.transferiereTokens( meinToken, account0, account1, betr, 180 );
             }
          } catch( Exception ex ) {
             out.println( "\n<br><font color='red'>Fehler beim MeinToken-Transfer. " +
                                "Ist die Passphrase bzw. der Private Key korrekt?<br>\n" + ex.getMessage() + "</font><br><br>\n" );
          }
       }
       session.setAttribute( "timestamp", "" + newTimestamp );
    %>
    
    <html>
    <head>
       <title>MeinToken-Smart-Contract-DApp</title>
       <meta http-equiv="content-type" content="text/html;charset=utf-8">
       <style>* { font-family: sans-serif; }</style>
    </head>
    <body bgcolor="#EEEEFF">
    
    <h2>DApp-Webseite zum MeinToken-Smart-Contract mit Java</h2>
    
    <form name="meinFormular" method="post"
          onSubmit="alert( 'OK betaetigen, circa 30 Sekunden auf das Mining warten und dann mit F5 refreshen.' )">
    <table border=0 cellspacing=9 cellpadding=0>
    <tr>
    <td valign="top">Contract:</td>
    <td><input type="text" name="contract" value='<%= contract %>' size='45' maxlength='42'><br></td>
    </tr>
    <tr>
    <td valign="top">Account0:</td>
    <td><input type="text" name="account0" value='<%= account0 %>' size='45' maxlength='42'>:
        <input type="text"    value='<%= kontostaende.get( 0 ) %>' size='12' maxlength='10' readonly> MeinToken<br>
        <input type="text" name="password" value='<%= password %>' size='45' maxlength='66'><br></td>
    </tr>
    <tr>
    <td valign="top">Account1:</td>
    <td><input type="text" name="account1" value='<%= account1 %>' size='45' maxlength='42'>:
        <input type="text"    value='<%= kontostaende.get( 1 ) %>' size='12' maxlength='10' readonly> MeinToken<br></td>
    </tr>
    <tr>
    <td valign="top">Betrag:</td>
    <td><input type="text"   name="betrag"    value='<%= betrag %>' size='12' maxlength='10'>
        <input type="submit" name="berechne"  value="starte Transfer"><br>
        <input type="hidden" name="timestamp" value='<%= "" + newTimestamp %>'></td>
    </tr>
    </table>
    </form>
    
    </body>
    </html>
    

    Überprüfen Sie die oben in MeinTokenTransfer.java eingetragenen Werte für DEFAULT_CONTRACT_ADRESSE, DEFAULT_PASSPHRASE_OR_PRIVKEY und DEFAULT_KEYSTORE_DIRS.

  6. Die Projektstruktur sieht jetzt so aus:

    [\MeinWorkspace\EthJavaDApp]
     |- pom.xml
     |- [src]
     |   '- [main]
     |       |- [java]
     |       |   '- [de]
     |       |       '- [meinefirma]
     |       |           '- [meinprojekt]
     |       |               |- EtherTransfer.java
     |       |               |- MeinToken.java
     |       |               '- MeinTokenTransfer.java
     |       '- [webapp]
     |           '- index.jsp
     |           '- [WEB-INF]
     |               '- web.xml
     |- [target]
     |   '- ...
     '- [web3j-3.3.1]
         |- [bin]
         |   '- web3j
         |   '- web3j.bat
         '- [lib]
             '- ...
    
  7. Falls noch nicht geschehen, starten Sie die Test-Ethereum-Blockchain:

    cd \MeinWorkspace\EthereumDemo

    starte-Test-Ethereum-Blockchain.bat

  8. Starten Sie den Jetty-Webserver mit der EthJavaDApp-Webanwendung:

    cd \MeinWorkspace\EthJavaDApp

    mvn jetty:run-war

    Warten Sie etwas, bis "Started Jetty Server" erscheint. Rufen Sie die Webseite auf:

    start http://localhost:8080/EthJavaDApp

  9. Merken Sie sich die jetzigen Kontostände, geben Sie die gewünschten Account-Adressen, die Passphrase bzw. den Private Key und den Betrag an zu transferierenden Tokens ein, und betätigen Sie den "starte Transfer"-Button. Warten Sie ausreichend lange, damit die Transaktion per Mining der Blockchain hinzugefügt wird. Anschließend refreshen Sie die Webseite, in den meisten Webbrowsern mit F5 oder mit Strg+R. Sie sehen die um den eingegebenen Betrag geänderten Kontostände.

  10. Wenn Sie die beiden Account-Adressen vertauschen, können Sie auch einen Transfer in die andere Richtung ausführen. Voraussetzung hierfür ist, dass der Account, von dem die Tokens transferiert werden, über ausreichend viele Ether verfügt, um die Transaktionsgebühren zu bezahlen, etwa indem Sie vorher mit Transfer von Ether mit Web3j und Java ein paar Ether transferieren.

  11. Sie erhalten beispielsweise:



Öffentliche Rinkeby-Test-Ethereum-Blockchain statt privater Blockchain

Diese Demo zeigt:

Die bisherigen Demos verwendeten eine private nur auf dem eigenen PC existierende Ethereum-Blockchain. In diesem Beispiel wird die öffentliche Rinkeby-Test-Ethereum-Blockchain verwendet.

Führen Sie die im Folgenden beschriebenen Schritte aus.

  1. Falls Sie bei den vorherigen Demos bereits das EthereumDemo-Projektverzeichnis angelegt haben, wechseln Sie in dieses Verzeichnis. Andernfalls legen Sie es an:

    cd \MeinWorkspace

    mkdir EthereumDemo

    cd EthereumDemo

    mkdir src

    tree /F

  2. Start-Skript:
    Erstellen Sie im EthereumDemo-Projektverzeichnis die Batchdatei starte-Rinkeby-Ethereum-Blockchain.bat mit folgendem Inhalt (in einer Zeile):

    geth --rinkeby --networkid 4 --datadir "Rinkeby-Blockchain" --rpc --rpcapi "db,eth,net,web3,personal,txpool" --rpccorsdomain "*" console 2>>rinkeby-geth.log

  3. Start der Rinkeby-Test-Ethereum-Blockchain:

    cd \MeinWorkspace\EthereumDemo

    starte-Rinkeby-Ethereum-Blockchain.bat

    Sie erhalten die Geth-JavaScript-Console, in der Sie Geth-JavaScript-Kommandos eingeben können.

  4. Stellen Sie zuerst in einem zweiten Kommandozeilenfenster sicher, dass Sie die gewünschte Test-Ethereum-Blockchain betreiben (und nicht die echte Ethereum-Blockchain):

    cd \MeinWorkspace\EthereumDemo

    type rinkeby-geth.log

    Ungefähr in der sechsten Zeile erscheint eine Meldung ähnlich zu:

    INFO [02-02|16:17:18] Initialising Ethereum protocol           versions="[63 62]" network=4
    

    Wichtig ist dabei die network-Nummer: Für Rinkeby muss sie 4 lauten.

  5. Sie können auch in der Geth-JavaScript-Console die network-Nummer überprüfen:

    admin.nodeInfo

  6. Beim erstmaligen Start der lokalen Rinkeby-Blockchain kann es stundenlang dauern, bis die komplette Blockchain auf den lokalen PC synchronisiert ist. Sie können dies in der Logdatei beobachten.

  7. Skript zur Abfrage der Kontostände:
    Falls Sie noch nicht wie oben vorgeschlagen im src-Verzeichnis die Datei checkAllBalances.js angelegt haben, legen Sie sie an.

  8. Account anlegen:
    Wechseln Sie wieder in das Fenster mit der Geth-JavaScript-Console. Legen Sie einen Account an (denken Sie sich ein schwierigeres Passwort aus und merken Sie es sich gut):

    web3.eth.accounts

    personal.newAccount( "Meine Ethereum-Test-Passphrase" )

    web3.eth.accounts

  9. Kontostände abfragen:
    Jetzt können Sie Kontostände abfragen. Führen Sie in der Geth-JavaScript-Console aus:

    loadScript( 'src/checkAllBalances.js' )

    Sie erhalten:

    0x39bbbe004272e72dba0c13a0e60443cfcceead3c:     balance: 0 ether
    
  10. Überprüfung der Keystore-Datei und der Verzeichnisstruktur:
    Führen Sie aus:

    dir \MeinWorkspace\EthereumDemo\Rinkeby-Blockchain\keystore

    Dort befindet sich die Keystore-Datei, beispielsweise:

    UTC--2018-02-02T16-17-18.123456789Z--39bbbe004272e72dba0c13a0e60443cfcceead3c
    
  11. Die Projektstruktur sieht jetzt so aus (je nachdem welche Beispiele Sie ausgeführt haben, können es mehr oder weniger Dateien sein):

    [\MeinWorkspace\EthereumDemo]
     |- build-MeinToken.bat
     |- MeinToken.address.priv.txt
     |- priv-geth.log
     |- rinkeby-geth.log
     |- starte-Rinkeby-Ethereum-Blockchain.bat
     |- starte-Test-Ethereum-Blockchain.bat
     |- [Private-Blockchain]
     |   '- ...
     |- [Rinkeby-Blockchain]
     |   |- [geth]
     |   |   |- [chaindata]
     |   |   |   '- ...
     |   |   '- ...
     |   '- [keystore]
     |       '- UTC--2018-02-02T16-17-18...
     |- [solc]
     |   '- ...
     |- [src]
     |   |- checkAllBalances.js
     |   |- genesis-block.json
     |   |- MeinToken.sol
     |   |- MeinTokenDeploy.js
     |   |- meinTokenJsTeil1.txt
     |   |- meinTokenJsTeil2.txt
     |   '- meinTokenJsTeil3.txt
     '- [target]
         |- MeinToken.abi
         '- MeinToken.bin
    

    Das Rinkeby-Blockchain\geth\chaindata-Verzeichnis enthält die Rinkeby-Blockchain-Daten und ist nach vollständiger Synchronisation mehrere Gigabyte groß.

  12. Ether zum Account transferieren:
    Da es sich um eine Test-Blockchain handelt, sind die Ether in dieser Blockchain wertlos. Trotzdem benötigen Sie Ether auf Ihrem Test-Account, wenn Sie weitere Versuche ausführen wollen. Unter https://faucet.rinkeby.io finden Sie hierzu eine Anleitung: Sie benötigen eine "Social network URL" von Facebook, Google Plus oder Twitter. Beispielsweise bei Google Plus geben Sie im Fenster "Was gibt's Neues bei dir?" Ihre Account-Adresse (mit vorangestelltem "0x") ein (z.B.: 0x39bbbe004272e72dba0c13a0e60443cfcceead3c) und klicken auf "[öffentlich] Posten". Anschließend öffnen Sie den Post in einem eigenen Fenster und kopieren die dann im Webbrowser angezeigte URL, beispielsweise: "https://plus.google.com/1016.../posts/ZZLx...". Diese URL geben Sie bei https://faucet.rinkeby.io ein und wählen rechts daneben bei "Give me Ether": "3 Ethers / 8 hours". Sie erhalten die Bestätigung "Funding request accepted". Anschließend warten Sie ca. 1 Minute auf das Mining.

  13. Da die Rinkeby-Ethereum-Blockchain eine öffentliche Blockchain ist, können Sie den Kontostand mit dem öffentlichen Etherscan-Internetdienst abfragen per: https://rinkeby.etherscan.io/address/{Meine-Account-Adresse} (ersetzen Sie "{Meine-Account-Adresse}" durch Ihre Account-Adresse).

  14. Ermitteln Sie die Kontostände auch erneut über die Geth-JavaScript-Console:

    loadScript( 'src/checkAllBalances.js' )

    Sie erhalten:

    0x39bbbe004272e72dba0c13a0e60443cfcceead3c:     balance: 3 ether
    
  15. Sehen Sie sich Infos und Statistiken zu Rinkeby an unter: https://www.rinkeby.io.



Smart Contract in die öffentliche Rinkeby-Blockchain deployen

Diese Demo zeigt:

Als Smart Contract wird der oben gezeigte MeinToken-Smart-Contract verwendet.

Führen Sie die im Folgenden beschriebenen Schritte aus.

  1. Alle oben unter Öffentliche Rinkeby-Test-Ethereum-Blockchain statt privater Blockchain beschriebenen Schritte müssen ausgeführt worden sein.

  2. Alle oben in dem Beispiel MeinToken-Smart-Contract-Demo beschriebenen Dateien werden benötigt.

  3. Führen Sie folgende Kommandos aus:

    cd \MeinWorkspace\EthereumDemo

    build-MeinToken.bat

  4. Falls noch nicht geschehen, starten Sie mit der oben erstellten Batchdatei die Rinkeby-Test-Ethereum-Blockchain:

    cd \MeinWorkspace\EthereumDemo

    starte-Rinkeby-Ethereum-Blockchain.bat

    Wahrscheinlich müssen Sie warten, bis die Blockchain synchronisiert ist.

  5. Der eigene Account muss über Ether verfügen:

    web3.eth.accounts

    loadScript( 'src/checkAllBalances.js' )

  6. Deployen Sie den MeinToken-Smart-Contract:

    personal.unlockAccount( web3.eth.accounts[0], "Meine Ethereum-Test-Passphrase" )

    loadScript( 'src/MeinTokenDeploy.js' )

    Sie erhalten:

    Contract transaction send: TransactionHash: 0x5759... waiting to be mined...
    

    Und nach vielleicht 30 Sekunden:

    Contract mined! Address: 0xf07a9248ac043cf039a6f76113b78f89d483b2c8
    
  7. Falls Sie eine der beiden folgenden Fehlermeldungen erhalten:

    Error: exceeds block gas limit

    Error: Contract transaction couldn't be found after 50 blocks

    Dann stimmt in der Regel etwas mit der angebotenen Gas-Menge nicht. Es darf weder zu wenig noch zu viel Gas angeboten werden. Passen Sie die Variable gasOffer in den Skripten src/meinTokenJsTeil3.txt bzw. src/MeinTokenDeploy.js geeignet an. Falls Sie noch nicht den genauen Wert berechnen wollen, können Sie im ersten Schritt "eth.getBlock( 'latest' ).gasLimit / 2" ansetzen.

  8. Überprüfen Sie die Beauftragung in der Logdatei rinkeby-geth.log. Dort erscheint eine Zeile ähnlich zu:

    INFO [02-02|12:13:14] Submitted contract creation              fullhash=0x5759... contract=0xF07a...
    
  9. Erfragen Sie die Adresse des deployten Smart Contracts:

    MeinToken.address

    Diese 40-stellige Hexadresse müssen Sie sich merken. Speichern Sie die Adresse in die Datei MeinToken.address.Rinkeby.txt.

  10. Führen Sie mit dem deployten Smart Contract einen Transfer von MeinToken durch. Falls noch nicht vorhanden, legen Sie vorher einen zweiten Account an. Überprüfen Sie, dass zumindest der erste Account über Ether verfügt. Lesen Sie vor und nach dem Transfer die MeinToken-Kontostände aus.

    personal.newAccount( "Meine Ethereum-Test-Passphrase" )

    web3.eth.accounts

    loadScript( 'src/checkAllBalances.js' )

    web3.eth.defaultAccount = web3.eth.accounts[0]

    personal.unlockAccount( web3.eth.defaultAccount, "Meine Ethereum-Test-Passphrase" )

    MeinToken.balanceOf( web3.eth.accounts[0] )

    MeinToken.balanceOf( web3.eth.accounts[1] )

    MeinToken.transfer( web3.eth.accounts[1], 19 );

    // Ca. 30 Sekunden auf das Mining warten.

    MeinToken.balanceOf( web3.eth.accounts[0] )

    MeinToken.balanceOf( web3.eth.accounts[1] )

    // Überprüfen Sie, dass der Ether-Kontostand von Ihrem Account um einen geringen Betrag reduziert wurde:

    loadScript( 'src/checkAllBalances.js' )

  11. Auch über den öffentlichen Etherscan-Internetdienst können Sie Ihre Transaktionen verfolgen: https://rinkeby.etherscan.io/address/{Meine-Account-Adresse} (ersetzen Sie "{Meine-Account-Adresse}" durch Ihre Account-Adresse).

  12. Mit dem weiter unten unter Analyse der Blöcke und Transaktionen beschriebenem Blöcke-Lese-JavaScript getTransactionsByAccount() können Sie die Transaktionen auch in der Rinkeby-Blockchain verfolgen. Übergeben Sie als Parameter Ihre Account-Adresse, um nicht unter zu vielen anderen Blöcken suchen zu müssen.



DApp-Webseite für den Smart Contract in der Rinkeby-Blockchain

Diese Demo zeigt:

  1. Alle oben unter Smart Contract in die öffentliche Rinkeby-Blockchain deployen beschriebenen Schritte müssen ausgeführt worden sein.

  2. DApp-Webseite für den Smart Contract mit Node.js:

    Ersetzen Sie in der Node.js-DApp-Webseite EthNodejsDApp/MeinTokenDAppWebseite.html in der Zeile const contractAddress = "0x..."; die Adresse des MeinToken-Smart-Contracts durch die neue Adresse aus der Rinkeby-Blockchain (gespeichert in MeinToken.address.Rinkeby.txt).

    Starten Sie die Node.js-DApp-Webseite:

    cd \MeinWorkspace\EthNodejsDApp

    start MeinTokenDAppWebseite.html

    Sie können wie gewohnt MeinToken-Beträge transferieren:

  3. DApp-Webseite für den Smart Contract mit Java:

    Sie können die neue Adresse des MeinToken-Smart-Contracts aus der Rinkeby-Blockchain und die Passphrase des ersten Accounts wahlweise entweder im Java-Sourcecode MeinTokenTransfer.java im Verzeichnis EthJavaDApp\src\main\java\de\meinefirma\meinprojekt in den beiden Zeilen
    public static final String DEFAULT_CONTRACT_ADRESSE = "0x...";
    public static final String DEFAULT_PASSPHRASE_OR_PRIVKEY = "...";
    eintragen, oder alternativ zur Laufzeit auf der Webseite eingeben.

    Starten Sie bei laufender Blockchain den Jetty-Webserver mit der EthJavaDApp-Webanwendung:

    cd \MeinWorkspace\EthJavaDApp

    mvn jetty:run-war

    Warten Sie etwas, bis "Started Jetty Server" erscheint. Rufen Sie die Webseite auf:

    start http://localhost:8080/EthJavaDApp

    Sie können wie gewohnt MeinToken-Beträge transferieren:



Truffle für einfache Entwicklung und schnelle Tests

Diese Demo zeigt:

Verwendet werden folgende Versionen:

Truffle kann mit Linux, Windows und Mac verwendet werden. Da die Installation und Verwendung unter Linux etwas einfacher als unter Windows ist, wird im Folgenden Truffle zwar unter Windows, aber in der bash von WSL (Windows-Subsystem für Linux) verwendet. Falls Sie direkt unter Linux (z.B. Ubuntu) arbeiten, können Sie die ersten Schritte einfach überspringen.

  1. Falls noch nicht geschehen, installieren Sie WSL (Windows-Subsystem für Linux). Voraussetzung hierfür ist Windows 10 in mindestens Version 1709. Rufen Sie die Versionsabfrage auf mit:

    winver

  2. Wechseln Sie in Ihr Workspace-Verzeichnis (z.B. \MeinWorkspace) und führen Sie folgende Kommandos aus:

    cd \MeinWorkspace

    mkdir EthTruffle

    cd EthTruffle

  3. Starten Sie die WSL-Bash, führen Sie zur Kontrolle und Orientierung folgende Kommandos aus, und updaten Sie Ihr Linux:

    bash

    MeinName@MeinPC:/mnt/d/MeinWorkspace/EthTruffle$
    

    cat /etc/issue

    Ubuntu 16.04.3 LTS \n \l
    

    pwd

    /mnt/d/MeinWorkspace/EthTruffle
    

    sudo apt-get update -y && sudo apt-get upgrade -y

  4. Installieren Sie in der bash den Node Version Manager nvm, Node.js, Truffle und Ganache CLI:

    curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash

    exec bash

    nvm --version

    nvm --help

    nvm ls

    nvm install node

    node -v

    npm -v

    npm install -g truffle ganache-cli

    ls -al ~

    ls -al ~/.nvm/versions/node/v9.5.0/bin

    ls -al ~/.nvm/versions/node/v9.5.0/lib/node_modules

    truffle version

    truffle init

    ls -al

    tree

    Sie erhalten:

    .
    +-- contracts
    ¦   +-- Migrations.sol
    +-- migrations
    ¦   +-- 1_initial_migration.js
    +-- test
    +-- truffle-config.js
    +-- truffle.js
    
  5. Ersetzen Sie im EthTruffle-Projektverzeichnis den Inhalt der Truffle-Konfigurationsdatei (setzen Sie dabei die korrekte Portnummer ein, siehe unten):
    truffle.js

    module.exports = {
       networks: {
          development: {
             host: "localhost",
             port: 8545,
             network_id: "*"
          }
       }
    };
    
  6. Für den zu erstellenden Test soll wieder der Smart Contract aus der oben gezeigten Mini-Token-Smart-Contract: MeinToken-Demo dienen.

    Entweder Sie kopieren manuell den Smart-Contract-Solidity-Sourcecode aus dem obigen MeinToken.sol in die neue Datei MeinToken.sol im Unterverzeichnis contracts.

    Oder, falls Sie obige Demo im Projektverzeichnis EthereumDemo ausgeführt haben, kopieren Sie die Datei in der bash:

    cp ../EthereumDemo/src/MeinToken.sol contracts/

    ls -al contracts

  7. Erstellen Sie für den MeinToken-Smart-Contract im migrations-Unterverzeichnis die Deploymentkonfigurationsdatei:
    2_MeinToken_migration.js

    var MeinToken = artifacts.require( "./MeinToken.sol" );
    
    module.exports = function( deployer ) {
       deployer.deploy( MeinToken, 999 );
    };
    

    Mit der Angabe 999 wird initial der Betrag von 999 MeinToken dem ersten Account gutgeschrieben (Sie können natürlich jeden beliebigen anderen Wert vorgeben).

  8. Erstellen Sie für den MeinToken-Smart-Contract im test-Unterverzeichnis das JavaScript-Testprogramm:
    MeinTokenTest.js

    const MeinToken = artifacts.require( "MeinToken" );
    
    contract( 'MeinToken', function( accounts )
    {
       let instance;
    
       before( async function () {
          instance = await MeinToken.deployed();
       } );
    
       it( "Initiale MeinToken-Kontostaende:   999 / 0", async function() {
          balance0 = await instance.balanceOf.call( accounts[0] );
          balance1 = await instance.balanceOf.call( accounts[1] );
          assert.equal( balance0.valueOf(), 999, "Account 0: Der MeinToken-Kontostand ist nicht 999" );
          assert.equal( balance1.valueOf(),   0, "Account 1: Der MeinToken-Kontostand ist nicht 0" );
       } );
    
       it( "Transfer von 11 MeinToken, danach: 988 / 11", async function() {
          await instance.transfer( accounts[1], 11 );
          balance0 = await instance.balanceOf.call( accounts[0] );
          balance1 = await instance.balanceOf.call( accounts[1] );
          assert.equal( balance0.valueOf(), 988, "Account 0: Der MeinToken-Kontostand ist nicht 988" );
          assert.equal( balance1.valueOf(),  11, "Account 1: Der MeinToken-Kontostand ist nicht 11" );
       } );
    
    } );
    

    Den initialen Betrag 999 müssen Sie an den oben in 2_MeinToken_migration.js eingetragenen Betrag angleichen.

  9. Kompilieren Sie die beiden Solidity-Sourcedateien:

    ls -al contracts

    truffle compile

    ls -al build/contracts/

    Sie erhalten zwei .json-Dateien.

  10. Truffle bietet verschiedene Test-Blockchains an, siehe Truffle Ethereum Clients. Mit "truffle develop" würden Sie eine Test-Blockchain mit JavaScript-Console erhalten. Im Folgenden soll stattdessen die üblichere Ganache-Blockchain verwendet werden:

    ganache-cli --help

    mkdir Ganache-Blockchain

    ganache-cli -d -i 66 --db Ganache-Blockchain

    Sie erhalten:

    Ganache CLI v6.0.3 (ganache-core: 2.0.2)
    
    Available Accounts
    ==================
    (0) 0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1
    (1) 0xffcf8fdee72ac11b5c542428b35eef5769c409f0
    ...
    
    Private Keys
    ==================
    (0) 4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d
    (1) 6cbed15c793ce57650b9877cf6fa156fbef513c4e6134f022a85b1ffdd59b2a1
    ...
    
    ...
    Listening on localhost:8545
    

    Es wurden automatisch 10 Accounts angelegt, die jeweils über 100 Ether verfügen. Diese Accounts und deren Private Keys werden angezeigt. Kopieren Sie sich zumindest den ersten Private Key, damit Sie weiter unten die Java-DApp-Webseite einsetzen können.

    Die verschiedenen mit Truffle startbaren Blockchains verwenden unterschiedliche Portnummern. Deshalb müssen Sie die Ausgabe "Listening on ..." genau beachten. Diese Angabe muss mit der in obiger truffle.js übereinstimmen.

  11. Resultierende Projektstruktur:

    Öffnen Sie ein zweites Kommandozeilenfenster, wechseln Sie wieder in die WSL-bash, und sehen Sie sich die resultierende Projektstruktur an:

    cd \MeinWorkspace\EthTruffle

    bash

    tree

    .
    +-- build
    ¦   +-- contracts
    ¦       +-- MeinToken.json
    ¦       +-- Migrations.json
    +-- contracts
    ¦   +-- MeinToken.sol
    ¦   +-- Migrations.sol
    +-- Ganache-Blockchain
    ¦   +-- !blockHashes!...
    ¦   ...
    +-- migrations
    ¦   +-- 1_initial_migration.js
    ¦   +-- 2_MeinToken_migration.js
    +-- test
    ¦   +-- MeinTokenTest.js
    +-- truffle-config.js
    +-- truffle.js
    
  12. Automatisierbarer Test des Smart Contracts:

    Der Test mit MeinTokenTest.js deployt temporär den MeinToken-Smart-Contract und führt das JavaScript-Testprogramm aus:

    truffle test

    Using network 'development'.
      Contract: MeinToken
        Initiale MeinToken-Kontostaende:   999 / 0 (39ms)
        Transfer von 11 MeinToken, danach: 988 / 11 (65ms)
      2 passing (126ms)
    

    Sie haben erfolgreich Ihren eigenen Smart Contract in die Ganache-Blockchain temporär deployt und in einem wiederholbaren und automatisierbaren Test ausgeführt und den Smart Contract getestet.
    Anders als in anderen Blockchains muss nicht lange auf das Mining gewartet werden.

  13. Deployen des Smart Contracts für manuelle Tests:

    Deployen Sie die Smart Contracts für weitere manuelle Tests (z.B. per DApp) in die Ganache-Blockchain:

    truffle migrate

    Using network 'development'.
    Running migration: 1_initial_migration.js
      Deploying Migrations...
      ... 0xb787070eb6a20cece690a7f9ded231a2a8c74466685156b4d244e745dc7a7b83
      Migrations: 0x26b4afb60d6c903165150c6f0aa14f8016be4aec
    Saving successful migration to network...
      ... 0x4ae2f8c27694fc1ed60f892e0bd5eaa845a03d8d8a505259c51ce45f6930f5a1
    Saving artifacts...
    Running migration: 2_MeinToken_migration.js
      Deploying MeinToken...
      ... 0xd60f0c6b6dd4d26cbfca7d1b735703d1baf43c2fbf3d7446cbe2b52d0e2d754f
      MeinToken: 0x0e696947a06550def604e82c26fd9e493e576337
    Saving successful migration to network...
      ... 0xe81f630f8d07e4121b0be7d30280de301edab5e28e675aa619a6d8e6f60d85b5
    Saving artifacts...
    
  14. Öffnen Sie die Truffle-Console:

    truffle console

    Darin können Sie Truffle-JavaScript-Kommandos ausführen, beispielsweise:

    web3.eth.accounts

    MeinToken.address

    MeinToken.at( MeinToken.address ).balanceOf.call( web3.eth.accounts[0] );

    MeinToken.at( MeinToken.address ).balanceOf.call( web3.eth.accounts[1] );

  15. Sehen Sie sich weiter unten an, wie Sie den Smart Contract in der Truffle-Test-Blockchain mit einer DApp-Webseite entweder mit Node.js oder mit Java ansprechen können: DApp-Webseite für den Smart Contract sowohl mit Truffle als auch mit Embark.



Embark für einfache Entwicklung und schnelle Tests

Diese Demo zeigt:

Verwendet werden folgende Versionen:

Wie bereits oben mit Truffle wird auch in dieser Demo wieder die bash von WSL (Windows-Subsystem für Linux) verwendet. Falls Sie direkt unter Linux (z.B. Ubuntu) arbeiten, können Sie einige Schritte einfach überspringen.

  1. Falls noch nicht geschehen, installieren Sie WSL, npm und Node.js wie oben für Truffle beschrieben.

  2. Wechseln Sie in Ihr Workspace-Verzeichnis (z.B. \MeinWorkspace):

    cd \MeinWorkspace

  3. Starten Sie die WSL-Bash, updaten Sie Ihr Linux, und installieren Sie Embark:

    bash

    sudo apt-get update -y && sudo apt-get upgrade -y

    npm -g install embark ethereumjs-testrpc

    ls -al ~

    ls -al ~/.nvm/versions/node/v9.5.0/bin

    ls -al ~/.nvm/versions/node/v9.5.0/lib/node_modules

    embark --version

    embark --help

  4. Starten Sie ein neues Embark-Projekt:

    embark new EthEmbark

    cd EthEmbark

    ls -al

    tree

    Sie erhalten:

    .
    +-- app
    ¦   +-- contracts
    ¦   +-- css
    ¦   +-- index.html
    ¦   +-- js
    +-- chains.json
    +-- config
    ¦   +-- blockchain.json
    ¦   +-- communication.json
    ¦   +-- contracts.json
    ¦   +-- development
    ¦   ¦   +-- genesis.json
    ¦   ¦   +-- password
    ¦   +-- storage.json
    ¦   +-- testnet
    ¦   ¦   +-- password
    ¦   +-- webserver.json
    +-- embark.json
    +-- package.json
    +-- test
        +-- contract_spec.js
    
  5. Für den zu erstellenden Test soll wieder der Smart Contract aus der oben gezeigten Mini-Token-Smart-Contract: MeinToken-Demo dienen.

    Entweder Sie kopieren manuell den Smart-Contract-Solidity-Sourcecode aus dem obigen MeinToken.sol in die neue Datei MeinToken.sol im Unterverzeichnis app/contracts.

    Oder, falls Sie obige Demo im Projektverzeichnis EthereumDemo ausgeführt haben, kopieren Sie die Datei in der bash:

    cp ../EthereumDemo/src/MeinToken.sol app/contracts/

    ls -al app/contracts

    Ersetzen Sie in der kopierten MeinToken.sol im app/contracts-Unterverzeichnis die Zeile:

    pragma solidity ^0.4.19;
    

    durch:

    pragma solidity ^0.4.17;
    
  6. Ersetzen Sie im config-Unterverzeichnis in der Konfigurationsdatei contracts.json die beiden Zeilen:

        "contracts": {
        }
    

    durch:

        "contracts": {
          "MeinToken": {
            "args": [ 999 ]
          }
        }
    
  7. Erstellen Sie für den MeinToken-Smart-Contract im test-Unterverzeichnis das JavaScript-Testprogramm:
    MeinTokenTest.js

    describe( "MeinToken", function() {
       before( function( done ) {
          this.timeout( 0 );
          var contractsConfig = {
             "MeinToken": {
               args: [999]
             }
          };
          EmbarkSpec.deployAll( contractsConfig, done );
       } );
    
       it( "Initiale MeinToken-Kontostaende:   999 / 0", function() {
          web3.eth.getAccounts( function( err, accounts ) {
             balance0 = MeinToken.balanceOf.call( accounts[0] );
             balance1 = MeinToken.balanceOf.call( accounts[1] );
             assert.equal( balance0.valueOf(), 999, "Account 0: Der MeinToken-Kontostand ist nicht 999" );
             assert.equal( balance1.valueOf(),   0, "Account 1: Der MeinToken-Kontostand ist nicht 0" );
          } )
       } );
    
       it( "Transfer von 11 MeinToken, danach: 988 / 11", function() {
          web3.eth.getAccounts( function( err, accounts ) {
             MeinToken.transfer( accounts[1], 11 );
             balance0 = MeinToken.balanceOf.call( accounts[0] );
             balance1 = MeinToken.balanceOf.call( accounts[1] );
             assert.equal( balance0.valueOf(), 988, "Account 0: Der MeinToken-Kontostand ist nicht 988" );
             assert.equal( balance1.valueOf(),  11, "Account 1: Der MeinToken-Kontostand ist nicht 11" );
          } )
       } );
    
    } );
    
  8. Resultierende Projektstruktur:

    tree

    .
    +-- app
    ¦   +-- contracts
    ¦   ¦   +-- MeinToken.sol
    ¦   +-- css
    ¦   +-- index.html
    ¦   +-- js
    +-- chains.json
    +-- config
    ¦   +-- blockchain.json
    ¦   +-- communication.json
    ¦   +-- contracts.json
    ¦   +-- development
    ¦   ¦   +-- genesis.json
    ¦   ¦   +-- password
    ¦   +-- storage.json
    ¦   +-- testnet
    ¦   ¦   +-- password
    ¦   +-- webserver.json
    +-- embark.json
    +-- package.json
    +-- test
        +-- contract_spec.js
        +-- MeinTokenTest.js
    
  9. Automatisierbarer Test des Smart Contracts:

    Der Test mit MeinTokenTest.js startet temporär eine eigene Test-Blockchain, deployt den Smart Contract, führt das JavaScript-Testprogramm aus und beendet die Test-Blockchain wieder:

    cd \MeinWorkspace\EthEmbark

    bash

    embark test

    Sie erhalten:

    MeinToken
    deployed contracts
        Initiale MeinToken-Kontostaende:   999 / 0
        Transfer von 11 MeinToken, danach: 988 / 11
      2 passing (4s)
    

    Sie haben erfolgreich Ihren eigenen Smart Contract in die Test-Blockchain deployt und in einem wiederholbaren und automatisierbaren Test ausgeführt und den Smart Contract getestet.

    Anders als in anderen Blockchains muss nicht lange auf das Mining gewartet werden.

  10. Manueller Test des Smart Contracts mit JavaScript-Kommandos:

    Ähnlich wie in der Geth-JavaScript-Console können Sie auch im Embark-Terminal-Dashboard direkt Web3-JavaScript-Kommandos ausführen.

    Starten Sie in der bash die in Embark integrierte Test-Blockchain:

    embark simulator

    Es werden die automatisch angelegten Accounts und deren Private Keys angezeigt. Kopieren Sie sich zumindest den ersten Private Key, damit Sie weiter unten die Java-DApp-Webseite einsetzen können.

    Öffnen Sie ein zweites Kommandozeilenfenster, starten Sie die bash, öffnen Sie das Embark-Dashboard, und deployen Sie den Smart Contract:

    cd \MeinWorkspace\EthEmbark

    bash

    embark run

    Im Embark-Dashboard (siehe Screenshot) ganz unten im "Console"-Abschnitt können Sie direkt JavaScript-Kommandos ausführen, beispielsweise:

    MeinToken.address

    MeinToken.balanceOf( web3.eth.accounts[0] )

    MeinToken.balanceOf( web3.eth.accounts[1] )

    MeinToken.transfer( web3.eth.accounts[1], 19 )

    MeinToken.balanceOf( web3.eth.accounts[0] )

    MeinToken.balanceOf( web3.eth.accounts[1] )

  11. Live-Blockchain:

    Selbstverständlich können Sie Embark nicht nur mit der Embark-Test-Blockchain verwenden, sondern auch mit allen anderen Ethereum-Blockchains. Hierzu verwenden Sie nicht das oben gezeigte Kommando embark simulator, sondern stattdessen embark blockchain.

  12. DApp-Webseite:

    Sehen Sie sich im folgenden Kapitel an, wie Sie den Smart Contract in der Embark-Test-Blockchain mit einer DApp-Webseite entweder mit Node.js oder mit Java ansprechen können.



DApp-Webseite für den Smart Contract sowohl mit Truffle als auch mit Embark

  1. Node.js-DApp-Webseite:

    Sie können den in die Truffle- oder Embark-Test-Blockchain deployten Smart Contract mit der oben unter DApp-Webseite für den Smart Contract mit Node.js erstellten DApp-Webseite verwenden.

    Ersetzen Sie in der Node.js-DApp-Webseite EthNodejsDApp/MeinTokenDAppWebseite.html in der Zeile const contractAddress = "0x..."; die Adresse des MeinToken-Smart-Contracts durch die neue Adresse aus der Truffle- bzw. Embark-Test-Blockchain, die Sie erhalten, indem Sie in der Truffle- bzw. Embark-Console eingeben:

    MeinToken.address

    Starten Sie bei laufender Test-Blockchain die Node.js-DApp-Webseite:

    cd \MeinWorkspace\EthNodejsDApp

    start MeinTokenDAppWebseite.html

    Die korrekten MeinToken-Kontostände werden angezeigt. Um MeinToken-Beträge zu transferieren geben Sie als Passphrase ein Minuszeichen ein ("-").

  2. Java-DApp-Webseite:

    Auch mit der DApp-Webseite für den Smart Contract mit Java können Sie den in die Truffle- oder Embark-Test-Blockchain deployten Smart Contract verwenden.

    Benötigt werden die mit MeinToken.address ermittelte Adresse des MeinToken-Smart-Contracts sowie der Private Key des Sender-Accounts (z.B. des ersten Accounts). Die Private Keys der Accounts werden beim Ausführen von "ganache-cli -d -i 66 --db Ganache-Blockchain" bzw. von "embark simulator" zum Starten der integrierten Test-Blockchain angezeigt.

    Sie können die Contract-Adresse und den Private Key wahlweise entweder im Java-Sourcecode MeinTokenTransfer.java im Verzeichnis EthJavaDApp\src\main\java\de\meinefirma\meinprojekt in den beiden Zeilen
    public static final String DEFAULT_CONTRACT_ADRESSE = "0x...";
    public static final String DEFAULT_PASSPHRASE_OR_PRIVKEY = "...";
    eintragen, oder alternativ zur Laufzeit auf der Webseite eingeben.

    Starten Sie bei laufender Test-Blockchain den Jetty-Webserver mit der EthJavaDApp-Webanwendung:

    cd \MeinWorkspace\EthJavaDApp

    mvn jetty:run-war

    Warten Sie etwas, bis "Started Jetty Server" erscheint. Rufen Sie die Webseite auf:

    start http://localhost:8080/EthJavaDApp

    Die korrekten MeinToken-Kontostände werden angezeigt, und Sie können wie gewohnt MeinToken-Beträge transferieren.



Verwendung des Oraclize-Dienstes für externe Informationsabfragen

Diese Demo zeigt:

Smart Contracts können Programmcode und Berechnungen ausführen und die Ergebnisse in der Blockchain speichern. Aber Smart Contracts können nicht mit der Außenwelt kommunizieren. Für einige Smart Contracts müssen aber Abfragen ausgeführt werden, um bestimmte "Real-World"-Bedingungen überprüfen zu können, beispielsweise Börsenkurse, Flugverspätungen oder Wetterdaten. Als Vermittler ("Data Feed") werden so genannte Oracles programmiert (z.B. in Solidity) und der Blockchain hinzugefügt. Ein Smart Contract kann das Oracle befragen, und das Oracle kann externe Schnittstellen z.B. per REST/JSON abrufen und das Ergebnis per Callback dem Smart Contract übermitteln. Siehe auch: Orakel-Dienste (Christoph Niemann), Types of Oracles, Building an Oracle for Ethereum (John Weldon), Oracles bring data to the blockchain (Jules Dourlens), Ethereum and Oracles (Vitalik Buterin), Oraclize.it: Data Carrier for decentralized Apps.

Einer der bekanntesten Dienstleister für solche Oracle-Dienste ist Oraclize.it. Ein Smart Contract, der diesen Dienst verwendet, wird im Folgenden präsentiert.

  1. Die Verwendung des Oraclize-Dienstes ist mit einer privaten Ethereum-Blockchain etwas aufwändiger, da dann zuerst eine Ethereum-Bridge installiert werden müsste. Deshalb wird hier die Rinkeby-Ethereum-Blockchain verwendet, wo das nicht erforderlich ist.

  2. Falls noch nicht geschehen, starten Sie mit der oben erstellten Batchdatei die Rinkeby-Test-Ethereum-Blockchain:

    cd \MeinWorkspace\EthereumDemo

    starte-Rinkeby-Ethereum-Blockchain.bat

    Wahrscheinlich müssen Sie warten, bis die Blockchain synchronisiert ist.

  3. Der eigene Account muss über Ether verfügen:

    web3.eth.accounts

    loadScript( 'src/checkAllBalances.js' )

    Falls Sie noch keine Accounts angelegt haben: Siehe oben Öffentliche Rinkeby-Test-Ethereum-Blockchain. Falls Sie Accounts haben, aber noch keine Ether: Siehe oben Ether zum Rinkeby-Account transferieren. Falls Sie bereits Ether übertragen haben, aber nach einem Neustart scheint der Ether-Betrag 0 zu sein: Wahrscheinlich müssen Sie einfach länger auf die Blockchain-Synchronisation warten. Ob der Rinkeby-Account über Ether verfügt, überprüfen Sie am besten mit https://rinkeby.etherscan.io/address/{Meine-Account-Adresse} (ersetzen Sie "{Meine-Account-Adresse}" durch Ihre Account-Adresse).

  4. Demonstriert werden soll die Kursabfrage vom britischen Pfund zum Euro. Dazu soll der über folgende REST-URL erreichbare Dienst verwendet werden:

    http://api.fixer.io/latest?symbols=USD,GBP

    Das JSON-Ergebnis lautet beispielsweise (je nach Webbrowser wird es unterschiedlich formatiert angezeigt):

    {
       "base":"EUR",
       "date":"2018-02-13",
       "rates": {
          "GBP":0.88935,
          "USD":1.2333
       }
    }
    
  5. Als diesen externen Dienst aufrufenden Smart Contract wird die Oraclize-Demo ExampleContract unter https://docs.oraclize.it/#ethereum-quick-start verwendet.

  6. Wie auf der Oraclize-Webseite empfohlen, wird die Remix Online Solidity Compiler IDE verwendet.

  7. Öffnen Sie die Remix Online Solidity Compiler IDE: http://remix.ethereum.org.

  8. Starten Sie ein neues Projekt, indem Sie auf der Webseite oben links auf das kleine Pluszeichen klicken.
    Geben Sie bei "File Name" ein: ExampleContract.sol

  9. In dem oberen mittleren leeren Fenster mit dem Titel "browser/ExampleContract.sol" fügen Sie den ExampleContract-Solidity-Sourcecode von https://docs.oraclize.it/#ethereum-quick-start ein (siehe auch den Screenshot weiter unten).

    Sehen Sie sich im ExampleContract-Solidity-Sourcecode insbesondere an:
    Wie per "import "github.com/oraclize/ethereum-api/oraclizeAPI.sol";" ein weiterer Solidity-Sourcecode importiert wird,
    wie in "contract ExampleContract is usingOraclize" der ExampleContract von usingOraclize abgeleitet wird,
    wie mit "function __callback(bytes32 myid, string result)" eine Callback-Methode implementiert wird,
    und wie mit "oraclize_query("URL", "json(http://api.fixer.io/latest?symbols=USD,GBP).rates.GBP") die externe JSON-REST-Schnittstelle abgefragt und ein Wert aus dem JSON-Response extrahiert wird.

  10. Klicken Sie im rechten Drittel oben auf den Tabulatorreiter "Compile" und dann auf den Button "Start to compile". Sie erhalten viele orangene Warnungen, aber keine roten Fehlermeldungen.

  11. Klicken Sie auf die Schaltfläche "Details", um die Kompilierergebnisse anzuzeigen. Unter "WEB3DEPLOY" finden Sie ein fertiges JavaScript-Programm zum Deployen des ExampleContract-Smart-Contracts. Dieses JavaScript könnten Sie in der Geth-JavaScript-Console ausführen. In dieser Demo soll jedoch stattdessen alles über die Remix-IDE ausgeführt werden.

  12. Verbinden Sie den Remix Online Solidity Compiler mit Ihrer Rinkeby-Blockchain:
    Klicken Sie im rechten Drittel oben auf den Tabulatorreiter "Run", wählen Sie bei Environment "Web3 Provider", bestätigen Sie "Are you sure you want to connect to an ethereum node?" sowie "Web3 Provider Endpoint" "http://localhost:8545".
    Oben rechts bei Environment wird angezeigt: "Rinkeby (4)".
    Und darunter bei Account erscheint Ihre Account-Adresse und dahinter in Klammern der Ether-Kontostand.

  13. Testen Sie die Verbindung:
    Geben Sie im unteren mittleren Fenster ganz unten neben dem ">"-Zeichen Geth-Kommandos ein, beispielsweise:
        web3.eth.accounts
    und betätigen Sie die Return-Taste.

  14. Deployen Sie Ihren ExampleContract-Smart-Contract in die Rinkeby-Blockchain:
    Geben Sie im unteren mittleren Fenster ganz unten neben dem ">"-Zeichen ein:
        web3.personal.unlockAccount( web3.eth.accounts[0], "Meine Ethereum-Test-Passphrase" )
    Betätigen Sie im mittleren Teil des rechten Fensters den "Create"-Button. Sie erhalten beispielsweise:

    > web3.personal.unlockAccount( web3.eth.accounts[0], "Meine Ethereum-Test-Passphrase" )
    true
    creation of ExampleContract pending...
    [block:1764901 txIndex:2] from:0x39b...ad3c, to:ExampleContract.(constructor), value:0 wei, 2 logs, data:0x606...0029, hash:0xfb1...bda4
    

    Der ExampleContract-Smart-Contract ist erfolgreich in die Rinkeby-Blockchain deployt.

    Klicken Sie im unteren mittleren Fenster auf den Details-Button, um sich weitere Informationen anzusehen. Beispielsweise sehen Sie dort die benötigte Gas-Menge.

  15. Wichtig: Merken Sie sich die Contract-Adresse, damit Sie den ExampleContract-Smart-Contract später wieder finden. Klicken Sie rechts neben "ExampleContract at 0x... (blockchain)" auf das Kopier-Icon und speichern Sie die kopierte Contract-Adresse in der Datei Oraclize.ExampleContract.address.Rinkeby.txt.

  16. Fragen Sie den anfänglich ermittelten EUR-GBP-Kurs ab, indem Sie rechts auf den EURGBP-Button klicken. Sie erhalten denselben Wert, wie oben bei der JSON-REST-Abfrage.

    Der Zugriff auf die externe JSON-REST-Schnittstelle hat funktioniert.

  17. Führen Sie die updatePrice()-Methode des ExampleContract-Smart-Contracts aus, indem Sie zuerst einen Unlock ausführen:
        web3.personal.unlockAccount( web3.eth.accounts[0], "Meine Ethereum-Test-Passphrase" )
    Und dann rechts auf den updatePrice-Button klicken. Sie erhalten:

    > web3.personal.unlockAccount( web3.eth.accounts[0], "Meine Ethereum-Test-Passphrase" )
    true
    transact to ExampleContract.updatePrice pending ...
    [block:1764970 txIndex:2] from:0x39...3c, to:ExampleContract.updatePrice() 0xfb...26, value:0 wei, 1 logs, data:0x67...28, hash:0x20...0e
    

    Das Ausführen der updatePrice()-Methode des ExampleContract-Smart-Contracts inklusive erneutem Zugriff auf die externe JSON-REST-Schnittstelle hat funktioniert.

    Falls Sie das Glück haben, dass sich der EUR-GBP-Kurs zwischenzeitlich verändert hat, sehen Sie den neuen Wert.

  18. Einfach nur den Kurswert in die Blockchain zu übertragen, macht natürlich keinen Sinn. Aber abhängig vom Kurswert könnte der Smart Contract weitere Entscheidungen treffen oder Aktionen starten. Unter http://dapps.oraclize.it finden Sie Beispiele für "Oraclize-based DApps".

  19. Theoretisch könnte der Oraclize-Dienst die übertragene Information fälschen. Um dies auszuschließen, bietet Oraclize Authenticity Proofs an.



Analyse der Blöcke und Transaktionen

Unter Common useful JavaScript snippets for geth finden Sie einige nützliche Geth-JavaScript-Skripte, beispielsweise das folgende getTransactionsByAccount():

  1. Fügen Sie das folgende Skript bei laufender Blockchain in der Geth-JavaScript-Console ein:

    function getTransactionsByAccount(myaccount, startBlockNumber, endBlockNumber) {
      if (endBlockNumber == null) {
        endBlockNumber = eth.blockNumber;
        console.log("Using endBlockNumber: " + endBlockNumber);
      }
      if (startBlockNumber == null) {
        startBlockNumber = endBlockNumber - 50;
        console.log("Using startBlockNumber: " + startBlockNumber);
      }
      console.log("Searching for transactions to/from account \"" + myaccount + "\" within blocks " +
                   startBlockNumber + " and " + endBlockNumber);
    
      for (var i = startBlockNumber; i <= endBlockNumber; i++) {
        if (i % 10 == 0) {
          console.log("Searching block " + i);
        }
        var block = eth.getBlock(i, true);
        if (block != null && block.transactions != null) {
          block.transactions.forEach( function(e) {
            if (myaccount == "*" || myaccount == e.from || myaccount == e.to) {
              console.log("  tx hash          : " + e.hash + "\n"
                + "   nonce           : " + e.nonce + "\n"
                + "   blockHash       : " + e.blockHash + "\n"
                + "   blockNumber     : " + e.blockNumber + "\n"
                + "   transactionIndex: " + e.transactionIndex + "\n"
                + "   from            : " + e.from + "\n" 
                + "   to              : " + e.to + "\n"
                + "   value           : " + e.value + "\n"
                + "   time            : " + block.timestamp + " " + new Date(block.timestamp * 1000).toGMTString() + "\n"
                + "   gasPrice        : " + e.gasPrice + "\n"
                + "   gas             : " + e.gas + "\n"
                + "   input           : " + e.input);
            }
          })
        }
      }
    }
    
  2. Anschließend können Sie sich in der Geth-JavaScript-Console bestimmte Transaktionen ansehen, beispielsweise so die letzten Transaktionen für alle Accounts:

    getTransactionsByAccount( "*" )

  3. Oder so für einen bestimmten Account in einem bestimmten Bereich von Blocknummern:

    getTransactionsByAccount( eth.accounts[0], 100, 200 )

  4. Angenommen Sie erhalten für die beiden letzten Blöcke:

      tx hash          : 0x7f3ef240d563e843f2cc577d63cc9f9382da8526aff4c7ea565db137c093fc4e
       nonce           : 110
       blockHash       : 0xeae4e8e1c9b2d73f35fc4f3d5013e37184bbf36ef4b27a303b6fccdcd80f4f4e
       blockNumber     : 9087
       transactionIndex: 0
       from            : 0x4597a26af9991b297b5ccc2a8c0966e9a1a17035
       to              : 0x63d7d5b64dc9cc0744dedf87971f8b0777d7e226
       value           : 10000000000000000000
       time            : 1517595662 Fri, 02 Feb 2018 18:21:02 GMT
       gasPrice        : 22000000000
       gas             : 4300000
       input           : 0x
    
      tx hash          : 0xba9d2cdbe9a1ea65a3551f0d8f39486acb0746f4c2a3ab6f20449eb698e959e5
       nonce           : 111
       blockHash       : 0x5964c99158f57252ee97043e267846dc2441472ed766feb89a85698ba19c9514
       blockNumber     : 9091
       transactionIndex: 0
       from            : 0x4597a26af9991b297b5ccc2a8c0966e9a1a17035
       to              : 0xa7818f6043df69bcf6c0db5d766e674d034dacfc
       value           : 0
       time            : 1517595743 Fri, 02 Feb 2018 18:22:23 GMT
       gasPrice        : 22000000000
       gas             : 4300000
       input           : 0xa9059cbb00000000000000000000000063d7d5b64dc9cc0744dedf87971f8b0777d7e226000000000000...
    

    Beim vorletzten Block werden 10 Ether (value: 10000000000000000000) vom Account 0x4597... an den Account 0x63d7... transferiert (per EtherTransfer).

    Beim letzten Block werden keine Ether transferiert (value: 0). Stattdessen führt der Account 0x4597... den Smart Contract unter 0xa781... aus (input: 0xa905...) (per MeinTokenTransfer).



Solidity-Plugin für JetBrains IntelliJ IDEA

Falls Sie JetBrains IntelliJ IDEA verwenden, können Sie das Intellij-Solidity-Plugin installieren:

  1. Hinweise zur Installation von IntelliJ IDEA gibt es unter: Install and set up IntelliJ IDEA. Weitere Hinweise finden Sie hier.

  2. Updaten Sie IntelliJ IDEA auf die aktuellste Version.

  3. Zur Installation des Intellij-Solidity-Plugins wählen Sie:
    File | Settings... | Plugins | Browse repositories... | Solidity | IntelliJ-Solidity | rechte Maustaste | Download and Install.

  4. Nach dem Neustart von IntelliJ IDEA können Sie Solidity-Dateien erstellen über:
    File | New | Smart contract.

  5. In der Version 2.0.4 bietet das Plugin Syntax-Highlighting, Auto-Vervollständigung (Code Completion) und Find Usages.

  6. Dies bietet allerdings auch der Remix Online Solidity Compiler, der darüber hinaus noch viele weitere Features bietet, wie beispielsweise Syntax-Fehler anzeigen, kompilieren, fertigen Web3-JavaScript-Code zum Deployen erstellen (unter Details | WEB3DEPLOY), und sogar Solidity-Code deployen, ausführen und debuggen.



Doku

Doku zu Kryptowährungen, Blockchain, Ethereum, Geth, Smart Contracts und Solidity:





Weitere Themen: Kryptowährungen, TechDocs
© 2018 Torsten Horn, Aachen