Was kommt nach der Blockchain? Teil 4: Hedera Hashgraph – Praktische Beispiele


14.10.2019 von

https://www.iteratec.de/fileadmin/Bilder/News/iteratec_logo.png https://www.iteratec.de/fileadmin/Bilder/News/iteratec_logo.png iteratec GmbH

In diese Blogserie geben wir einen tieferen Einblick zu den Themen IOTA und Hashgraph und die dahinter liegenden Konzepte:

Aufbauend auf den theoretischen Grundlagen des Hashgraph-Algorithmus des vorherigen Artikels wird sich dieser Artikel der Praxis widmen. Basis dafür ist die Hedera-Plattform und das von Hedera angebotene Java SDK (Version 0.6.1).

Eine erste Erkenntnis beim Schreiben des Artikels war, dass solche Plattformen sehr schnelllebig in einem sehr frühen Entwicklungsstadium sind. Begonnen hatte ich den Artikel und die ersten Beispielimplementierungen mit der Version 0.2.X des SDK. Aus verschiedenen Gründen verzögerte sich die Fertigstellung und ich musste immer wieder die Implementierungen auf die neueste SDK Version umstellen, um die Funktionalität des aktuellen Standes zu nutzen. Dies war dann auch immer mit Überraschungen verbunden.

Mittlerweile wurden z. B. die Fees (Transaktionsgebühren) eingeführt, die es am Anfang so in der Implementierung nicht gab. Diese sind aber aktuell noch im Beta-Stadium und man sieht, dass die Dokumentation sich innerhalb einer Woche ändern kann.

Die Hedera-Plattform

Hedera ist ein Public Distributed Ledger für den Bau und die Bereitstellung dezentraler Anwendungen und Services. Die Hedera-Plattform bietet die Nutzung von drei unterschiedlichen Services an:

  • Kryptowährung
  • Smart Contracts
  • Fileservice

Das Distributed Ledger von Hedera besteht aktuell aus permissioned Nodes, die vom Hedera Governing Council verwaltet und betrieben werden. Das Netzwerk soll sich nach Aussage auf der Website von Hedera aber im Laufe der Zeit zu einem permissionless Modell entwickeln. Wann das sein wird, ist bisher nicht klar.

Plattform-Feature

Die Hedera-Plattform bietet für die drei angebotenen Services jeweils APIs an, die sich in Queries und Transactions strukturieren.

Über die Query APIs kann man existierende Informationen abfragen. Diese Anfragen gehen an eine einzelne Node. Zu solchen Abfragen gehören z. B. Infos zu einem Account.

Transaktionen sind hingegen Anfragen an das gesamte Netz, bei denen eine Konsensbildung stattfindet. Dies ist z. B. der Fall bei einem Transfer von HBARs (die Hedera Coins) von einem Account zu einem anderen.

Transaktionen, die an einen Node übertragen wurden, werden mit einer Response bestätigt. Dazu gibt es unterschiedliche Response-Typen, die unterschiedliche Informationen verfügbar machen. Die wichtigsten sind aktuell Receipts und Records.

Receipts liefern minimale Informationen dazu, ob die Transaktion erfolgreich zur Konsensbildung übertragen wurden.

Records liefern detailliertere Informationen zu einer Transaktion, wie z. B. den Transaktionszeitstempel.

In der hier betrachteten Version 0.6.1 des SDK sind die Records als Response-Objekt allerdings schon als „deprecated“ gekennzeichnet. Es gibt aber eine Methode, um Records zu einem Account separat abfragen.
Wie bereits erwähnt wurden mittlerweile Fees eingeführt, die für Transaktionen und Abfragen zu entrichten sind. Diese werden mit Tinybars (1hbar (ℏ) = 100.000.000 tinybars (tℏ)) bezahlt. Bei der Einrichtung eines Test-Accounts bei Hedera erhält man 1000ℏ, um damit seine Beispiele oder Testanwendungen implementieren und testen zu können.

Nachfolgend finden sich einige Implementierungsbeispiele für die Services „Cryptocurrency Account“ und „File“. Den Service „Smart Contract“ werde ich später in einem separaten Beitrag beleuchten.

Implementierungsbeispiele

Voraussetzungen

Für die Nutzung des Hedera Distributed Ledger ist ein Zugang notwendig. Aktuell wird ein Mainnet und ein Testnet betrieben. Diese stellen aufgrund ihres Entwicklungstands aktuell noch unterschiedliche Services zur Verfügung. Die nachfolgenden Beispiele wurden mit einem Testnet-Account umgesetzt.

Bevor die Implementierung starten kann sind die folgenden Schritte durchzuführen:

  1. Anlegen eines Profils im Hedera-Portal. Dies erfordert auch die Verifikation der Identität (z. B. mit dem Personalausweis)
  2. Verbindung mit dem Testnet herstellen. Dazu ist es notwendig, ein Schlüsselpaar bestehend aus einem Public und Private Key zu erzeugen
  3. Einrichten der Entwicklungsumgebung (Hedera Java SDK importieren)

Alle notwendigen Details dazu sind gut beschrieben in der Dokumentation von Hedera zu finden.
Nach der vollständigen Registrierung erhält man eine Account ID. Die Infos zu dieser ID und den verfügbaren Netzwerkknoten befinden sich im Portal (s. Abbildung 1) nachdem die obigen Schritte 1 und 2 durchgeführt wurden.

Die Daten sind wichtig, da diese in die (versteckte) Konfigurationsdatei mit dem Namen „.env“ einzutragen sind. Im SDK befindet sich eine Beispieldatei „.env.sample“.

Nachfolgend die ausgefüllte „.env“-Datei als Beispiel.

# Network Node ID and Address
NODE_ID= 0.0.3
NODE_ADDRESS= 0.testnet.hedera.com:50211

# Operator ID and Private Key
OPERATOR_ID= 0.0.10…
OPERATOR_KEY= 30…

Die Account ID ist die Operator ID und der Operator Key ist der Private Key, den man erzeugt hat. Der Node wird über eine ID und eine Adresse definiert, sodass man auch unterschiedliche Nodes verwenden kann.

Durch die freie Definition der Nodes kann nun auch die gleichzeitige Verfügbarkeit von Informationen auf unterschiedlichen Nodes getestet werden. Dazu muss in der Implementierung nur ein Client mit den entsprechenden Parametern erzeugt werden.

High-level-Methoden

Neben den Transaktionen und Queries, die in der Dokumentation beschrieben sind und in den nachfolgenden Beispielen verwendet werden, gibt es auch noch einige High-level-Methoden, die man direkt im Client aufrufen kann. Allerdings scheint die Umstellung des APIs im Rahmen der Einführung der Fees noch nicht abschlossen, da einige dieser Methoden zwar noch im SDK existieren, aber im folgenden Beispiel aufgrund der Einführung der Fees zu einer Exception (INSUFFICIENT_TX_FEE) führen.

Die beschriebene Anlage eines Accounts konnte bis zur „Aktivierung“ der Fees noch mit der folgenden Methode erfolgen.

…
AccountId newAccountId = client.createAccount(newKey.getPublicKey(), initialBalance);
…

Dies ist ein Beispiel für die Schnelllebigkeit der Plattform in diesem frühen Entwicklungsstadium.

Cryptocurrency Account Services

Mithilfe des Cryptocurrency Account Services der Hedera-Plattform ist es möglich, Konten zu verwalten und Coin-Transaktionen in HBAR (ℏ) auszuführen.

Wie jede andere Cryptowährung, können auch die HBAR-Coins (ℏ) zwischen Partnern getauscht, bzw. zum Begleichen anfallender Gebühren genutzt werden, die für die Nutzung der Hedera-Services als Transaktionsgebühren anfallen.

Um einen Transfer von Coins ausführen zu können, werden zunächst Accounts benötigt, zwischen denen die Coins transferiert werden. Dies erfolgt mit dem Service AccountCreateTransaction().

Anlegen eines Accounts

Der Service AccountCreateTransaction() erstellt einen neuen Account im Hedera-Netzwerk. Für diesen Account wird eine neue Account ID generiert, die zum Senden und Empfangen von HBARs zwischen anderen Benutzern im Netzwerk verwendet werden kann. Das nachfolgende Beispiel zeigt den Beispielcode für die Anlage eines Accounts.

public static AccountId createAccount() throws HederaException{
  // Generate a Ed25519 private, public key pair
  var newKey = Ed25519PrivateKey.generate();
  var newPublicKey = newKey.getPublicKey();

  // Establish a connection to a Hedera client
  var client = Helper.createHederaClient();

  //Initial balance of tinybars for the new account
  var initialBalance = 1000;
  var tx = new AccountCreateTransaction(client)
    .setKey(newKey.getPublicKey())
    .setInitialBalance(initialBalance)
    .setTransactionFee(80_000_000);

  // This will wait for the receipt to become available
  var receipt = tx.executeForReceipt();
    
  return receipt;
}

Für die Anlage eines Accounts ist zunächst ein neuer Private und Public Key zu generieren. Anschließend wird der eigentliche Account angelegt. Im obigen Beispiel ist nur die Anlage eines Accounts mit Basic-Daten gezeigt. Es gibt noch einige Erweiterungen, die bei der Anlage eines Accounts gesetzt werden können.

Als Ergebnis erhält man aus dem Receipt-Objekt eine neue Account ID. Diese setzt sich zusammen aus der RealmNumber, der ShardNumber und der AccountNumber. 

accountId = 0.0.62402

Bedeutung hat aktuell nur die AccountNumber. Die beiden anderen Werte sind momentan immer 0.
Zur Account ID kann man über den Service AccountInfoQuery() Infos zum Account abfragen. In dem zurückgelieferten Response-Objekt befindet sich u. a. die Balance.

public static AccountInfo getAccountInfo(AccountId accountId, Client client) throws HederaEx-ception {
  var query = new AccountInfoQuery(client)
    .setAccountId(accountId);
  
  AccountInfo account = query.execute();
  return account;
}

Das AccountInfo-Objekt besitzt die nachfolgend gezeigten Informationen, auf die man zugreifen kann. Hier ist die initial angelegte Balance von 1000 tℏ aus dem obigen Beispiel erkennbar.

accountID {
  accountNum: 62402
}
contractAccountID: "000000000000000000000000000000000000f3c2"
proxyAccountID {
}
key {
  ed25519: "7\326\237\317\330Q\237M\316g\343\241\260\360\340Z\b\322\212……."
}
balance: 1000
generateSendRecordThreshold: 9223372036854775807
generateReceiveRecordThreshold: 9223372036854775807
autoRenewPeriod {
  seconds: 2592000
}

Mit diesem zweiten Account ist jetzt der Weg geebnet, um einen Transfer von Coins durchzuführen.

Cryptocurrency transferieren

Der Service CryptoTransferTransaction() ermöglicht den Transfer von Tinybars (tℏ) von einem Konto auf ein anderes Konto im Hedera-Netzwerk.

Der oder die Absender und Empfänger werden über ihre Account ID identifiziert. In dem folgenden Beispiel werden 1.000.000 tℏ von einem Konto (10291) auf ein anderes Konto (auf das oben erstellte Konto 62402) übertragen.

public static TransactionReceipt transferCryptocurrency(AccountId senderAccountId, 
  AccountId recipientAccountId, 
  long transferAmount, 
  Client client) throws HederaException {
  
  CryptoTransferTransaction ct;
  Transaction tx;

  ct = new CryptoTransferTransaction(client);
  ct.addSender(senderAccountId, transferAmount)
  ct.addRecipient(recipientAccountId, transferAmount)
  ct.setTransactionFee(90000);
  
  tx = ct.build();
  // we are sending from the operator we do not need to explicitly sign the transaction
  TransactionReceipt receipt = tx.executeForReceipt();
  return receipt;
}

Die Balance vor und nach der Übertragung in beiden Konten sieht folgendermaßen aus.

Vor Übertragung:
     balance 10291: 98518051073
     balance 62402: 1012

Nach Übertragung:
     balance 10291: 98516967018
     balance 62402: 1000916

Die Transaktion muss von allen Absender-Accounts signiert werden. In der aktuellen Implementierung des Clients ist eine automatische Signierung durch den Haupt-Account (der für die Transaktionen zahlt) umgesetzt. Die notwendigen Daten dafür werden aus der weiter oben beschriebenen „.env“-Datei geholt. Da der obige Absender identisch zum Haupt-Account ist, muss dieser in dem Beispiel nicht explizit signieren.

Wenn der Absender nicht über genügend Guthaben auf seinem Konto verfügt, um die Transaktion abzuwickeln, schlägt die Transaktion fehl und die Tinybars werden nicht auf das Empfängerkonto überwiesen.

Wenn die zu transferierenden Tinybars aus verschiedenen Accounts stammen, müssen die Quell-Accounts auch jeweils die Transaktion signieren. Im nachfolgenden Beispiel ist der Key für den zweiten Account (62402) zur Signatur angegeben. Der Haupt-Account (10291) muss nicht explizit angegeben werden.

…
ct = new CryptoTransferTransaction(client);
for (int i=0; i< senderAccounts.length; i++) {
  ct.addSender(senderAccounts[i], transferAmount);
}
ct.addRecipient(recipientAccountId, transferAmount);
ct.setTransactionFee(180000);

tx = ct.build();
for (int i=1; i< senderAccounts.length; i++) {
  tx.sign(key[i]);
}
…

Dieser Codeausschnitt ist die generische Variante zum Beispiel der Überweisung zwischen zwei Accounts.
In dem Beispiel werden jeweils 5000 tℏ vom Account 10291 und 62402 an den Account 69192 übertragen. Die Balances der Accounts vor dem Transfer sehen folgendermaßen aus.

Vor Übertragung:
     balance 10291: 98507842535
     balance 62402: 985535
     balance 69192: 30619

Nach dem Transfer kann man sehen, dass der Account 69192 etwa 10.000 tℏ mehr besitzt (abzüglich Fees).

Nach Übertragung:
     balance 10291: 98507699945
     balance 62402: 980408
     balance 69192: 40492

Im Detail kann man die gesamte Verrechnung inklusive Fees aus dem Transaction Record ableiten. Diesen erhält man über den Service AccountRecordQuery().

Account Records anzeigen

Der Service AccountRecordQuery() liefert alle Datensätze für ein Konto für Ein- und Auszahlungen, die in den letzten 24 Stunden über dem vom Benutzer festgelegten Schwellenwert lagen. Die Abfrageantwort enthält den Header und die Konto-ID sowie die einzelnen Transaction Records.

Die Implementierung dieser Abfrage ist relativ simpel, wie das folgende Beispiel zeigt:

public static CryptoGetAccountRecordsResponse getAccountRecords(
    AccountId accountId, 
    Client client) throws HederaException 
{
  // Create AccountRecordsQuery() object
  var query = new AccountRecordsQuery(client)
    .setAccountId(accountId);

  CryptoGetAccountRecordsResponse respons = query.execute();
  return respons;
}

Im Datensatz zur obigen Transaktion (je 5000 tℏ aus 10291 und 62402 an 69192) können die einzelnen Buchungen genau aufgeschlüsselt werden. Nachfolgend werden nur die wichtigsten Teile aus dem gesamte Transaction Record für den jeweiligen Account gezeigt, um die Buchungen einfach nachzuvollziehen.

Für den Account 10291 hatten wir vor und nach dem Transfer der 5000 tℏ folgende Beträge.

Vor Übertragung:
     balance 10291: 98507842535
 
Nach Übertragung:
     balance 10291: 98507699945
 
In dem zugehörigen Transaction Record ist erkennbar, dass neben den 5000 tℏ noch Fees in Höhe von 136326 tℏ und 1264 tℏ angefallen sind. Die Summe der Abzüge führt dann zu dem obigen Ergebnis nach dem Transfer.

…
  accountAmounts {
    accountID {
      accountNum: 10291
    }
    amount: -136326
  }
…
  accountAmounts {
    accountID {
      accountNum: 10291
    }
    amount: -1264
  }
…
  accountAmounts {
    accountID {
      accountNum: 10291
    }
    amount: -5000
  }
…

Für den zweiten Account, von dem 5000 tℏ abgebucht werden, sieht es ähnlich aus. Es wurden 5000 tℏ abgebucht und 127 tℏ Fees sind angefallen.

Vor Übertragung:
     balance 62402: 985535

Nach Übertragung:
     balance 62402: 980408

…
  accountAmounts {
    accountID {
      accountNum: 62402
    }
    amount: -5000
  }
  accountAmounts {
    accountID {
      accountNum: 62402
    }
    amount: -127
  }
…

Der „Gewinner“ ist der dritte Account als der Empfänger der 10.000 tℏ. Wie man sieht, sind aber nach der Transaktion nicht alle 10.000 tℏ vorhanden.

Vor Übertragung:
     balance 69192: 30619

Nach Übertragung:
     balance 69192: 40492

Im zugehörigen Transaction Record ist erkennbar, dass zwar alle 10.000 tℏ transferiert, aber gleichzeitig wieder 127 tℏ als Fees abgezogen wurden.

accountAmounts {
    accountID {
      accountNum: 69192
    }
    amount: 10000
  }
  accountAmounts {
    accountID {
      accountNum: 69192
    }
    amount: -127
  }
…

Es wurden hier nicht alle Cryptocurrency Account Queries oder Transaktionen als Beispiele betrachtet, da diese alle sehr ähnlich verwendet werden. In der Dokumentation finden sich alle Transaktionen und Queries. Dort sind alle Methoden einzeln mit Beispiel-Implementierungen aufgeführt. Die Herausforderung besteht aktuell noch darin, zu ergründen, ob und wie alle Parameter wirklich funktionieren und wie stabil die Implementierungen sind. Nachfolgend ein Beispiel aus dieser Rubrik.

Der Service CryptoTransferTransaction() des nachfolgenden Beispiel-Codes wäre das Rückgabeobjekt vom Typ CryptoTransferTransaction.

new CryptoTransferTransaction(client)
  .addSender(senderAccounts[0], 100)
  .addRecipient(recipientAccountId, 100)
  .setTransactionFee(10000);

Wenn wir jetzt eine kleine Änderung vornehmen und das Ganze noch signieren mit .sign(), was man aufgrund der Dokumentation als erstes versuchen wird, dann führt die Methode sign() zu einem Objekt vom Typ Transaction.

new CryptoTransferTransaction(client)
  .addSender(senderAccounts[0], 100)
  .addSender(senderAccounts[1], 100)
  .addRecipient(recipientAccountId, 200)
  .setTransactionFee(10000)
  .sign(key[1]);

Der Versuch für mehrere Accounts, die die Transaktion signieren müssen, einen Transfer auszuführen, wird bei dieser Implementierung zur Laufzeit mit einer Exception scheitern - auch wenn es erstmal keine Compiler-Fehler gibt.

Die Lösung dieses Problems erschließt sich erst, wenn man sich die Implementierung im SDK genauer ansieht. Da die Transaktion von allen Beteiligten zu signieren ist, muss die Transaktion erst „gebaut“ werden, um anschließend signierbar zu sein. Dies ist im folgenden Code veranschaulicht.

cryptoTransferTransaction ctx = new CryptoTransferTransaction(client)
  .addSender(senderAccounts[0], 100)
  .addSender(senderAccounts[1], 100)
  .addRecipient(recipientAccountId, 200)
  .setTransactionFee(10000)

Transaction tx = ct.build();

tx.sign(key[1]);

File Service API

Der Hedera-File-Service ermöglicht es, externe Daten in einem öffentlichen Ledger zu verankern. Bei den externen Daten kann es sich z. B. um den Hash eines Dokuments oder einer Datenbank handeln. Aber man kann auch ein eigenes klassisches PDF ablegen. Auch wenn das Ledger sicherlich nicht wirklich als File-System für große Dateien gedacht ist.

Die Services sind dabei in zwei Gruppen aufgeteilt:

  • File Service Transactions (Möglichkeiten zum Anlegen, Andern oder Löschen von Dateien)
  • File Service Query (Abfragen von Informationen zu einer Datei)


Nachfolgend eine Betrachtung der wesentlichen Services.

Create File

Der Service FileCreateTransaction() erstellt eine neue Datei, die über ihre ID im Ledger referenziert wird.
Diese ID erhält man bei einer erfolgreichen Ausführung der Anlage der Datei im Ledger in der Response.

Bei Ausführung des Beispiel-Codes unten, wird in dem Receipt eine File ID zurückgeliefert, die folgendermaßen aussieht:

file ID: 0.0.61975

Über diese ID kann die Datei später eindeutig identifiziert werden (z. B. bei File-Zugriffen).

Details zu den einzelnen Parametern können in der API-Dokumentation nachgelesen werden. Ich möchte hier nur auf einzelne Parameter eingehen.

public static TransactionReceipt createFile(
          Client client, 
          byte[] fileContents, 
          long duration, 
          Ed25519PrivateKey[] keys) throws HederaException
{
  FileCreateTransaction ftx;
  Transaction tx;

  //create new FileCreateTransaction 
  ftx = new FileCreateTransaction(client);
  ftx.setExpirationTime(Instant.now().plus(Duration.ofSeconds(duration)));
  for (int i=0; i< keys.length; i++) {    
    ftx.addKey((keys[i]).getPublicKey());
  }
  ftx.setContents(fileContents);
  ftx.setTransactionFee(42_000_000 * keys.length);
  
  //build FileCreateTransaction 
  tx = ftx.build();
  
  //sign transaction
  for (int i=1; i< keys.length; i++) {
    tx.sign(keys[i]);
  }
  TransactionReceipt receipt = tx.executeForReceipt();
  return receipt;      
}

In dem Codebeispiel wird eine Datei angelegt, die mehrere Eigentümer hat. Das kann Sinn machen, wenn Dokumente wie z. B. ein Führerschein betrachtet werden. In diesem Fall wäre sowohl die Führerscheinstelle als auch der Inhaber Eigentümer des Dokuments.

Dazu müssen über die Methode addKey() alle Eigentümer (identifiziert über ihren Public Key) hinzugefügt werden, die anschließend auch die Transaktion mit der Methode sign() signieren müssen. Der Eigentümer des Accounts (im obigen Fall key[0]) signiert per Definition immer und muss nicht explizit angegeben werden.

Über die Methode setExpirationTime() kann die Lebensdauer der Datei definiert werden. Nach Ablauf dieser Zeit kann nicht mehr auf den Content zugegriffen werden.

Mit der Einführung der Transaction Fee ist diese auch entsprechend bei Ausführung von Transaktionen zu setzen. Zu den Kosten gibt es eine Übersicht bei Hedera. Für die Operation FileCreate werden 41.666.666,67 tℏ angegeben. Sollen mehrere Eigentümer angegeben werden, wie im obigen Beispiel zwei, dann muss die doppelte Anzahl angeben werden, da wir sonst eine entsprechende Exception erhalten.

Transaktionen sind in Hedera auf eine Größe von 4KB beschränkt. Ist eine Datei aber größer, dann muss diese zerlegt und mit dem Service FileAppendTransaction() schrittweise um die fehlenden Inhalte erweitert werden.

Append File

Mit dem Service FileAppendTransaction() kann einer existierenden Datei Content hinzufügt werden. Dazu benötigt man nur die File ID.

Aufbauend auf dem schon beschriebenen Service FileCreateTransaction() lassen sich damit auch größere Dateien über den File Service ablegen.

Der nachfolgende Code zeigt eine Lösung, bei der die zu speichernde Datei zerlegt und mit dem Service FileCreateTransaction() erstellt und anschließend die fehlenden Inhalte mit dem Service FileAppendTransaction() ergänzt werden. Zur besseren Übersicht sind einzelne Code-Teile in dem Beispiel nicht ausgeführt und durch „…“ ersetzt.

public static TransactionReceipt createLargeFile(
      byte[] fileContents, 
      long duration, Ed25519PrivateKey[] key) throws HederaException 
{
  final int FILE_PART_SIZE = 1000; // 1K bytes
  …
  int numParts = fileContents.length / FILE_PART_SIZE;
  int remainder = fileContents.length % FILE_PART_SIZE;
  …
  //find first parts of the file
  firstPartBytes = Helper.copyBytes(0, FILE_PART_SIZE, fileContents);
  ….
  // create the new file
  TransactionReceipt receipt = createFile(firstPartBytes, duration, key);
  …
  // append the all parts
  for (int i = 1; i < numParts; i++) {
    byte[] partBytes = Helper.copyBytes(
      i * FILE_PART_SIZE,
      FILE_PART_SIZE, 
      fileContents);
    …
    appendReceipt = appendFile(partBytes, myFileId);
    …
  }
  // append the rest of the file
  …
  return receipt;
}

Die im obigen Beispiel aufgerufene appendFile()-Methode, die der Service FileAppendTransaction() ausführt, ist sehr einfach.

public static TransactionReceipt appendFile(
        byte[] fileContents, 
        FileId fileId) throws HederaException
{
  var client = Helper.createHederaClient();
  var tx = new FileAppendTransaction(client)
    .setFileId(fileId)
    .setContents(fileContents)
    .setTransactionFee(42_000_000);

  TransactionReceipt receipt = tx.executeForReceipt();
  return receipt;
}

Neben den beiden detaillierter vorgestellten File-Service-Transaktionen gibt es noch Services zum Löschen oder Updaten von Dateien. Das Updaten ist bezüglich der Parameter im Wesentlichen zum Service FileCreateTransaction(), nur dass hier die File ID angeben werden muss, um zu identifizieren, welche Datei geändert werden soll.

Informationen zu einer Datei anzeigen

Mithilfe des Services FileInfoQuery() können verschiedene Informationen zu einer Datei gelesen werden. Diese bekommt man allerdings nur, wenn die Datei noch nicht abgelaufen ist. In der betrachteten Version des Testnet scheint dies aktuell nicht mehr zu funktionieren, da man auch für abgelaufene Dateien Informationen bekommt. In einer früheren Version hatte ich dies bereits getestet und bekam damals auch eine entsprechende Fehlermeldung.

…
var tx = new FileInfoQuery(client)
    .setFileId(fileID);

FileInfo info = tx.execute();
… 

Nach Ausführung erhält man die folgenden Infos im FileInfo-Objekt zurück:

keys: [302a300506032b6570032100ebeba69760b5b7d52c27867cbc857dee741722d9adf0df1dfebf819d0c321c0b, 302a300506032b65700321008cbb4189fcb252cf0a6f1bd32b7a35cf4b31691e58ba2731deb37e220a81f536]
file experation time: 2019-09-18T14:49:27Z
file size: 10
file Id: 0.0.61974
file deleted: false

In der Aktuellen Version des Testnets scheint es so zu sein, dass für diese Query noch keine Fee notwendig ist, auch wenn in der Dokumentation bereits eine Fee für die Query ausgewiesen wurde.

Ähnlich einfach kann man sich den Content der Datei anzeigen lassen.

Datei löschen

Das Löschen einer Datei ist in der aktuellen Umsetzung etwas widersprüchlich zur existierenden Dokumentation.

Im obigen Beispiel, in dem eine Datei mit zwei Eigentümern angelegt wurde, ist es aktuell auch notwendig, dass beide Eigentümer die Transaktion zum Löschen signieren müssen, sonst erhält man eine Exception.

…
  FileDeleteTransaction dftx = new FileDeleteTransaction(client);
  dftx.setFileId(fileID);
  dftx.setTransactionFee(6_000_000 *2);
  dftx.build();
  Transaction tx = dftx.sign(key);
…

Das sign() fehlt in der konkreten Dokumentation zum Service FileDeleteTransaction() und passt so auch nicht zu der Beschreibungen der File Service API.

Zusammenfassung

Was ist nun die Erkenntnis, die ich nach den vier Blogartikeln gewonnen habe? Beide DLTs IOTA und Hashgraph bieten einen vielversprechenden theoretischen Ansatz. Beide sind noch sehr jung in ihrer Umsetzung und müssen noch den Nachweis erbringen, dass sie im großen (versprochenen) Stil funktionieren. Aus Sicht der Implementierungsmöglichkeiten ist IOTA für mein Gefühl aktuell etwas besser aufgestellt. Einerseits existieren mehr und konkretere Informationen, sowohl von IOTA als auch aus der Community. Andererseits fallen hier bisher keine Kosten für Transaktionen an. Der Weg zur Umsetzung von ersten Prototypen ist somit relativ kurz. Des Weiteren gibt es über einen Tangle Browser eine gute Transparenz darüber, welche Daten im Tangle liegen. Was bei IOTA noch immer schwer wiegt, ist der noch existierende Coordinator. Erst mit dessen Entfernung kann der wirkliche funktionale Nachweis erbracht werden.

Hashgraph bzw. genauer gesagt das Hedera Distributed Ledger ist noch sehr stark in der Entwicklungsphase. Dies merkt man mit jedem Update des SDK. Aus Sicht der Implementierung eines Prototyps, ist hier ständig Bewegung im Code. Die Dokumentation bei Hedera ist aber so gut, dass man schnell mit einfachen Beispielen starten kann. In den Details scheint sie immer wieder in Teilen der Entwicklung voraus und in anderen Teilen hinterher zu hinken. Ein weiteres Problem ist, dass aktuell nicht so einfach reproduzierbar ist, welche Daten wirklich wie im Hashgraph liegen. Es gibt kein eigenes Tooling, wie den Tangle Browser bei IOTA, um sich Transaktionen bzw. die Daten direkt im Graphen anzusehen.

Alle bisherigen Ideen (wie z. B. die Möglichkeiten mehrere Eigentümer für ein Asset zu definieren) sind vielversprechend, müssen sich aber erst in der Praxis beweisen.

Da der Hashgraph-Algorithmus patentiert ist, ist es schwer abzusehen, wie sich die Kosten für Transaktionen entwickeln werden.

Diesen Artikel bewerten
 
 
 
 
 
 
 
0 Bewertungen (0 %)
Bewerten
 
 
 
 
 
 
1
5
0
 

Artikel im Warenkorb:

0