Hyperledger Fabric (HLF) ist eine Open-Source-Plattform, die DLT-Technologie (Distributed Ledger Technology) verwendet, um Anwendungen zu entwickeln, die in einer Unternehmensnetzwerkumgebung funktionieren, die von einem Konsortium von Organisationen mithilfe von Zugriffsregeln erstellt und gesteuert wird (mit Berechtigung).
Die Plattform unterstützt intelligente Verträge in HLF-Begriffen - Kettencodes, die in allgemeinen Sprachen wie Golang, JavaScript, Java erstellt wurden, im Gegensatz zu beispielsweise Ethereum, das eine vertragsorientierte Solidity-Sprache mit eingeschränkter Funktionalität verwendet (LLL, Viper usw.).

Das Entwickeln und Testen von Kettencodes kann aufgrund der Notwendigkeit, eine erhebliche Anzahl von Komponenten des Blockchain-Netzwerks bereitzustellen, ein ziemlich langwieriger Prozess sein, bei dem viel Zeit für das Testen von Änderungen aufgewendet wird. Dieser Artikel beschreibt einen Ansatz zur schnellen Entwicklung und zum Testen von HLF Golang-Smart-Verträgen mithilfe der CCKit- Bibliothek.
HLF-basierte Anwendung
Aus Sicht des Entwicklers besteht die Blockchain-Anwendung aus zwei Hauptteilen:
- On-Chain - Intelligente Verträge (Programme), die in einer isolierten Umgebung des Blockchain-Netzwerks ausgeführt werden und die Regeln für die Erstellung und Zusammensetzung von Transaktionsattributen festlegen. In einem intelligenten Vertrag sind die Hauptaktionen das Lesen, Aktualisieren und Löschen von Daten aus dem Status des Blockchain-Netzwerks. Es sollte betont werden, dass beim Löschen von Daten aus einem Status Informationen darüber verbleiben, dass diese Daten vorhanden waren.
- Off-Chain ist eine Anwendung (z. B. eine API), die über das SDK mit der Blockchain-Umgebung interagiert. Unter Interaktion versteht man das Aufrufen von Smart Contract-Funktionen und das Überwachen von Smart Contract-Ereignissen. Externe Ereignisse können Datenänderungen im Smart Contract verursachen, während Ereignisse im Smart Contract Aktionen in externen Systemen auslösen können.
Daten werden normalerweise über den Blockchain-Netzwerkknoten „Home“ gelesen. Um Daten aufzuzeichnen, sendet die Anwendung Anforderungen an die Knoten von Organisationen, die an der „Genehmigungsrichtlinie“ eines bestimmten Smart-Vertrags teilnehmen.
Zur Entwicklung von Off-Chain-Code (API usw.) wird ein spezielles SDK verwendet, das die Interaktion mit Blockchain-Knoten, das Sammeln von Antworten usw. kapselt. Für HLF gibt es SDK-Implementierungen für Go ( 1 , 2 ), Node.Js und Java
Hyperledger Fabric-Komponenten
Kanal
Ein Kanal ist ein separates Subnetz von Knoten, das eine isolierte Blockkette (Ledger) sowie den aktuellen Status (Schlüsselwert) der Blockkette (Weltstatus) unterstützt, die für den Betrieb intelligenter Verträge verwendet wird. Ein Host kann auf eine beliebige Anzahl von Kanälen zugreifen.
Transaktion
Eine Transaktion in Hyperledger Fabric ist eine atomare Aktualisierung des Status einer Blockkette, das Ergebnis der Ausführung der Chaincode-Methode. Eine Transaktion besteht aus einer Anforderung zum Aufrufen einer Chaincode-Methode mit einigen vom aufrufenden Knoten signierten Argumenten (Transaktionsvorschlag) und einer Reihe von Antworten (Transaktionsvorschlagsantwort) von den Knoten, auf denen die Transaktion „bestätigt“ wurde (Bestätigung). Die Antworten enthalten Informationen zu den sich ändernden Schlüssel-Wert-Paaren des Status der Blockkette des Lese- / Schreibsatzes und Dienstinformationen (Signaturen und Zertifikate von Knoten, die die Transaktion bestätigen). Weil Blockketten einzelner Kanäle sind physisch getrennt, eine Transaktion kann nur im Kontext eines Kanals durchgeführt werden.
Die "klassischen" Blockchain-Plattformen wie Bitcoin und Ethereum verwenden den von allen Knoten ausgeführten Ordering-Execution-Transaktionszyklus, wodurch die Skalierbarkeit des Blockchain-Netzwerks eingeschränkt wird.

Hyperledger Fabric verwendet eine Transaktionsausführungs- und -verteilungsarchitektur mit drei Hauptoperationen:
Ausführung ( Ausführung ) - Erstellung durch einen intelligenten Vertrag, der auf einem oder mehreren Netzwerkknoten ausgeführt wird, Transaktionen - atomare Änderungen im Status einer verteilten Registrierung ( Bestätigung )
Bestellung - Bestellung und Gruppierung von Transaktionen in Blöcken durch den spezialisierten Bestellservice unter Verwendung eines steckbaren Konsensalgorithmus.
Validieren - Überprüfung der vom Besteller stammenden Transaktionen durch Netzwerkknoten, bevor Informationen von diesen in ihre Kopie der verteilten Registrierung aufgenommen werden

Mit diesem Ansatz können Sie die Transaktionsausführungsphase vor dem Eintritt in das Blockchain-Netzwerk ausführen und den Betrieb von Netzwerkknoten horizontal skalieren.
Kettencode
Ein Kettencode, der auch als Smart Contract bezeichnet werden kann, ist ein in Golang, JavaScript (HLF 1.1+) oder Java (HLF 1.3+) geschriebenes Programm, das die Regeln zum Erstellen von Transaktionen definiert, die den Status einer Blockkette ändern. Das Programm wird gleichzeitig auf mehreren unabhängigen Knoten eines verteilten Netzwerks von Blockchain-Knoten ausgeführt, wodurch eine neutrale Umgebung für die Ausführung intelligenter Verträge geschaffen wird, indem die Ergebnisse der Programmausführung auf allen Knoten abgeglichen werden, die für die "Bestätigung" der Transaktion erforderlich sind.
Der Code muss eine Schnittstelle implementieren, die aus Methoden besteht:
type Chaincode interface {
- Die Init- Methode wird beim Instanziieren oder Aktualisieren des Codecodes aufgerufen. Diese Methode führt die erforderliche Initialisierung des Status des Codecodes durch. Es ist wichtig, im Methodencode zu unterscheiden, ob es sich bei dem Aufruf um eine Instanziierung oder ein Upgrade handelt, damit Sie versehentlich nicht die Daten initialisieren (zurücksetzen), die während des Betriebs des Codecodes bereits einen Status ungleich Null erhalten haben.
- Die Invoke- Methode wird aufgerufen, wenn auf eine Funktion des Codecodes zugegriffen wird. Diese Methode funktioniert mit dem Status intelligenter Verträge.
Der Kettencode wird auf den Peers des Blockchain-Netzwerks installiert. Auf Systemebene entspricht jede Instanz des Codes einem separaten Docker-Container, der an einen bestimmten Netzwerkknoten angeschlossen ist und Dispatching-Aufrufe zur Ausführung des Codes ausführt.
Im Gegensatz zu intelligenten Ethereum-Verträgen kann die Verkettungslogik aktualisiert werden. Dies erfordert jedoch, dass alle Knoten, auf denen sich der Codecode befindet, eine aktualisierte Version installieren.
In Reaktion auf einen Aufruf der Kettencodefunktion von außen über das SDK erzeugt der Kettencode eine Änderung des Status der Blockkette ( Lese- / Schreibsatz ) sowie Ereignisse. Ein Kettencode bezieht sich auf einen bestimmten Kanal und kann Daten in nur einem Kanal ändern. Wenn der Host, auf dem der Code installiert ist, auch Zugriff auf andere Kanäle hat, kann gleichzeitig in der Logik des Codes Daten von diesen Kanälen gelesen werden.
Spezielle Kettencodes zum Verwalten verschiedener Aspekte des Betriebs eines Blockchain-Netzwerks werden als Systemkettencodes bezeichnet.
Endorsement Policy
Eine Genehmigungsrichtlinie definiert Konsensregeln auf der Ebene der Transaktionen, die von einem bestimmten Kettencode generiert werden. Die Richtlinie legt die Regeln fest, die bestimmen, welche Kanalknoten eine Transaktion erstellen sollen. Zu diesem Zweck muss jeder der in der Genehmigungsrichtlinie angegebenen Knoten die Verkettungsmethode (Schritt "Ausführen") ausführen und eine "Simulation" durchführen. Anschließend werden die signierten Ergebnisse vom SDK gesammelt und überprüft, das die Transaktion initiiert hat (alle Simulationsergebnisse müssen identisch sein.) Signaturen aller für die Richtlinie erforderlichen Knoten müssen vorhanden sein. Als nächstes sendet das SDK die Transaktion an den Besteller. Danach empfangen alle Knoten, die Zugriff auf den Kanal haben, die Transaktion über den Besteller und führen den Schritt "Validieren" aus. Es ist wichtig zu betonen, dass nicht alle Kanalknoten am Schritt "Ausführen" teilnehmen müssen.
Die Genehmigungsrichtlinie wird zum Zeitpunkt der Instanziierung oder Aktualisierung des Codes festgelegt. In Version 1.3 wurde es möglich, Richtlinien nicht nur auf der Ebene des Kettencodes, sondern auch auf der Ebene der einzelnen zustandsbasierten Endorsement-Schlüssel festzulegen. Beispiele für Genehmigungsrichtlinien:
- Knoten A, B, C, D.
- Die meisten Kanalknoten
- Mindestens 3 Knoten von A, B, C, D, E, F.
Ereignis
Ein Ereignis ist ein benannter Datensatz, mit dem Sie einen „Update-Feed“ des Status der Blockchain-Kette veröffentlichen können. Der Satz von Ereignisattributen definiert den Kettencode.
Netzwerkinfrastruktur
Host (Peer)
Ein Host ist mit einer beliebigen Anzahl von Kanälen verbunden, für die er Zugriffsrechte hat. Der Host verwaltet seine Version der Blockkette und den Status der Blockkette und bietet auch eine Umgebung zum Ausführen von Kettencodes. Wenn der Host nicht Teil der Genehmigungsrichtlinie ist, muss er nicht mit Kettencodes eingerichtet werden.
Auf der Ebene der Host-Software kann der aktuelle Status der Blockkette (Weltstatus) in LevelDB oder in CouchDB gespeichert werden. Der Vorteil von CouchDB ist die Unterstützung umfangreicher Abfragen mit MongoDB-Syntax.
Besteller
Der Transaktionsverwaltungsdienst akzeptiert signierte Transaktionen als Eingabe und stellt sicher, dass die Transaktionen in der richtigen Reihenfolge auf die Netzwerkknoten verteilt werden.
Der Besteller führt keine intelligenten Verträge aus und enthält keine Blockketten und Blockkettenzustände. Im Moment (1.3) gibt es zwei Implementierungen von orderer - ein Development Solo und eine auf Kafka basierende Version, die Crash-Fehlertoleranz bietet. Eine Implementierung des Auftraggebers , der den Widerstand gegen das falsche Verhalten eines bestimmten Teils der Teilnehmer unterstützt (byzantinische Fehlertoleranz), wird Ende 2018 erwartet.
Identitätsdienste
In einem Hyperledger Fabric-Netzwerk haben alle Mitglieder Identitäten, die anderen Mitgliedern bekannt sind (Identität). Zur Identifizierung wird die Public-Key-Infrastruktur (PKI) verwendet, über die X.509-Zertifikate für Organisationen, Infrastrukturelemente (Knoten, Besteller), Anwendungen und Endbenutzer erstellt werden. Infolgedessen kann der Zugriff auf Lese- und Änderungsdaten durch Zugriffsregeln auf Netzwerkebene, auf einem einzelnen Kanal oder in der Logik eines intelligenten Vertrags gesteuert werden. Im selben Blockchain-Netzwerk können mehrere Identifikationsdienste verschiedener Typen gleichzeitig arbeiten.
Implementierung des Codecodes
Chaincode kann als ein Objekt betrachtet werden, das über Methoden verfügt, die eine bestimmte Geschäftslogik implementieren. Im Gegensatz zum klassischen OOP kann ein Kettencode keine Attributfelder haben. Um mit dem Status zu arbeiten, dessen Speicher von der HLF-Blockchain-Plattform bereitgestellt wird, wird die Ebene ChaincodeStubInterface verwendet , die beim Aufruf der Methoden Init und Invoke übergeben wird. Es bietet die Möglichkeit, Funktionsaufrufargumente zu empfangen und Änderungen am Status der Blockkette vorzunehmen:
type ChaincodeStubInterface interface {
In dem auf Solidity entwickelten Ethereum-Smart-Vertrag hat jede Methode eine öffentliche Funktion. Im Hyperledger Fabric-Kettencode in den Methoden Init und Invoke mit der Funktion ChaincodeStubInterface . GetArgs () können Sie die Argumente des Funktionsaufrufs in Form eines Arrays von Byte-Arrays abrufen, während das erste Element des Arrays beim Aufruf von Invoke den Namen der Chaincode-Funktion enthält. Weil Der Aufruf einer beliebigen Chaincode-Methode durchläuft die Invoke-Methode. Wir können sagen, dass dies eine Implementierung des Front-Controller-Musters ist.
Wenn wir beispielsweise die Implementierung der Standard-Ethereum-Schnittstelle für das ERC-20- Token in Betracht ziehen, sollte der Smart Contract die folgenden Methoden implementieren:
- totalSupply ()
- balanceOf (Adresse _Besitzer)
- Übertragung (Adresse _to, uint256 _Wert)
und andere. Bei der HLF-Implementierung muss der Funktionscode Invoke in der Lage sein, Fälle zu behandeln, in denen das erste Argument zum Aufrufen von Aufrufen den Namen der erwarteten Methoden enthält (z. B. "totalSupply" oder "balanceOf"). Ein Beispiel für die Implementierung des ERC-20-Standards ist hier zu sehen.
Chaincode-Beispiele
Neben der Dokumentation zu Hyperledger Fabric gibt es einige weitere Beispiele für Kettencodes :
Die Implementierung der Kettencodes in diesen Beispielen ist ziemlich ausführlich und enthält eine Menge sich wiederholender Logik zur Auswahl der aufgerufenen Routing-Funktionen. Überprüfen der Anzahl der Argumente, json marshalling / unmarshalling:
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { function, args := stub.GetFunctionAndParameters() fmt.Println("invoke is running " + function)
Eine solche Organisation des Codes führt zu einer Verschlechterung der Lesbarkeit des Codes und möglichen Fehlern wie diesen , wenn Sie einfach vergessen haben, die Eingabedaten zu entfernen. In den Präsentationen zu den HLF-Entwicklungsplänen wird eine Überarbeitung des Ansatzes zur Entwicklung von Kettencodes erwähnt, insbesondere die Einführung von Anmerkungen in Java-Kettencodes usw. Die Pläne beziehen sich jedoch auf die Version, die erst 2019 erwartet wird. Die Erfahrung mit der Entwicklung intelligenter Verträge hat zu dem Schluss geführt, dass das Entwickeln und Testen von Kettencodes einfacher ist, wenn Sie die Grundfunktionen in einer separaten Bibliothek auswählen.
CCKit - eine Bibliothek zum Entwickeln und Testen von Kettencodes
Die CCKit- Bibliothek fasst die Praxis des Entwickelns und Testens von Kettencodes zusammen. Im Rahmen der Entwicklung von Chaincode- Erweiterungen wurde als Beispiel die OpenZeppelin-Erweiterungsbibliothek für Ethereum-Smart-Verträge verwendet. CCKit verwendet die folgenden Architekturlösungen:
Weiterleiten von Anrufen an intelligente Vertragsfunktionen
Routing bezieht sich auf den Algorithmus, mit dem die Anwendung auf eine Clientanforderung reagiert. Dieser Ansatz wird beispielsweise in fast allen http-Frameworks verwendet. Der Router verwendet bestimmte Regeln, um die Anforderung und den Anforderungshandler zu binden. In Bezug auf einen Kettencode dient dies dazu, den Namen der Kettencodefunktion mit der Handlerfunktion zu verknüpfen.
In den neuesten Beispielen für intelligente Verträge, beispielsweise in der Versicherungs-App , wird die Zuordnung zwischen dem Namen der Kettencodefunktion und der Funktion im Golang-Code des Formulars verwendet:
var bcFunctions = map[string]func(shim.ChaincodeStubInterface, []string) pb.Response{
Der CCKit-Router verwendet einen ähnlichen Ansatz wie der http-Router sowie die Möglichkeit, den Anforderungskontext für die Chaincode-Funktion und die Middleware-Funktionen zu verwenden
Der Kontext des Aufrufs der Funktion des Codes
Ähnlich wie der http-Anforderungskontext, der normalerweise Zugriff auf die http-Anforderungsparameter hat, verwendet der CCKit-Router den Kontext des Aufrufs der Smart Contract- Funktion, die eine Abstraktion über shim.ChaincodeStubInterface darstellt . Der Kontext kann das einzige Argument für den Handler der Verkettungsfunktion sein. Über ihn kann der Handler die Argumente des Funktionsaufrufs sowie Zugriff auf Hilfsfunktionen für die Arbeit mit dem Status des intelligenten Vertrags (Status), das Erstellen von Antworten (Antwort) usw. erhalten.
Context interface { Stub() shim.ChaincodeStubInterface Client() (cid.ClientIdentity, error) Response() Response Logger() *shim.ChaincodeLogger Path() string State() State Time() (time.Time, error) Args() InterfaceMap Arg(string) interface{} ArgString(string) string ArgBytes(string) []byte SetArg(string, interface{}) Get(string) interface{} Set(string, interface{}) SetEvent(string, interface{}) error }
Weil Der Kontext ist eine Schnittstelle, in bestimmten Kettencodes kann er erweitert werden.
Middleware-Funktionen
Funktionen der Zwischenverarbeitung (Middleware) werden vor dem Aufruf des Handlers der Codemethode aufgerufen, haben Zugriff auf den Kontext des Aufrufs der Codemethode und auf die nächste Zwischenfunktion oder direkt auf den Handler der Methode des nächsten (next). Middleware kann verwendet werden für:
- Konvertieren von Eingabedaten (im folgenden Beispiel sind p.String und p.Struct Middleware)
- Einschränkungen beim Zugriff auf die Funktion (z. B. Eigentümer. Nur )
- Abschluss des Anforderungsverarbeitungszyklus
- Aufruf der nächsten Zwischenverarbeitungsfunktion vom Stapel
Datenstrukturkonvertierung
Die Kettencode-Schnittstelle nimmt an, dass der Eingabe ein Array von Byte-Arrays zugeführt wird, deren Elemente jeweils ein Attribut der Kettencode-Funktion sind. Um zu verhindern, dass aus den Funktionsaufrufargumenten in jedem Handler der Verkettungsfunktion ein manuelles Daten-Marshalling vom Byte-Array zum Golang-Datentyp (int, string, struct, array) erfolgt, werden die erwarteten Datentypen zum Zeitpunkt der Erstellung der Routing-Regel im CCKit-Router festgelegt und der Typ wird automatisch konvertiert . Im folgenden Beispiel erwartet die carGet- Funktion ein Argument vom Typ string, und die carRegister- Funktion erwartet eine CarPayload- Struktur. Das Argument wird auch benannt, wodurch der Handler seinen Wert aus dem Kontext anhand des Namens abrufen kann. Ein Beispiel für einen Handler wird unten angegeben. Protobuf kann auch verwendet werden, um das Verkettungsdatenschema zu beschreiben.
r.Group(`car`). Query(`List`, cars).
Die automatische Konvertierung (Marshalling) wird auch beim Schreiben von Daten in den Status eines intelligenten Vertrags und beim Erstellen von Ereignissen verwendet (der Golang-Typ wird in ein Array von Bytes serialisiert).
Tools zum Debuggen und Protokollieren von Kettencodes
Zum Debuggen des Codes können Sie die Debug- Erweiterung verwenden, die intelligente Vertragsmethoden implementiert, mit denen Sie das Vorhandensein von Schlüsseln im Status des intelligenten Vertrags überprüfen und den Wert direkt nach Schlüssel lesen / ändern / löschen können.
Für die Protokollierung im Kontext eines Aufrufs einer Chaincode-Funktion kann die Log () -Methode verwendet werden, die eine Instanz des in HLF verwendeten Loggers zurückgibt.
Intelligente Vertragsmethoden Zugriffskontrollmethoden
Im Rahmen der Eigentümererweiterung werden grundlegende Grundelemente zum Speichern von Informationen über den Eigentümer des instanziierten Kettencodes und Zugriffsmodifikatoren (Middleware) für intelligente Vertragsmethoden implementiert.
Intelligente Tools zum Testen von Verträgen
Das Bereitstellen des Blockchain-Netzwerks, das Installieren und Initialisieren von Kettencodes ist eine ziemlich komplizierte Einrichtung und ein langwieriger Vorgang. Die Zeit für die Neuinstallation / Aktualisierung des Smart-Vertragscodes kann durch Verwendung des DEV-Modus des Smart-Vertrags verkürzt werden. Die Aktualisierung des Codes ist jedoch weiterhin langsam.
Das Shim- Paket enthält eine Implementierung von MockStub , die Aufrufe des Codes für den Code umschließt und dessen Betrieb in der HLF-Blockchain-Umgebung simuliert. Mit MockStub erhalten Sie fast sofort Testergebnisse und können die Entwicklungszeit verkürzen. Wenn wir das allgemeine Funktionsschema des Codes in HLF berücksichtigen, ersetzt MockStub im Wesentlichen das SDK, sodass Sie die Funktionen des Codes aufrufen können, und ahmt die Startumgebung des Codes auf dem Host nach.

Der MockStub aus der HLF-Lieferung enthält die Implementierung fast aller Methoden der shim.ChaincodeStubInterface- Schnittstelle. In der aktuellen Version (1.3) fehlen jedoch einige wichtige Methoden wie GetCreator. Weil Kettencode kann diese Methode verwenden, um ein Zertifikat eines Transaktionserstellers für die Zugriffskontrolle zu erhalten. Für eine maximale Abdeckung in Tests ist die Fähigkeit, einen Stub dieser Methode zu haben, wichtig.
Die CCKit-Bibliothek enthält eine erweiterte Version von MockStub , die die Implementierung der fehlenden Methoden sowie Methoden zum Arbeiten mit Ereigniskanälen usw. enthält.
Beispiel für einen Kettencode
Erstellen wir beispielsweise einen einfachen Kettencode zum Speichern von Informationen über zugelassene Autos
Datenmodell
Der Status des Codecodes ist der Schlüsselwertspeicher, in dem der Schlüssel eine Zeichenfolge und der Wert ein Array von Bytes ist. Die grundlegende Praxis besteht darin, jonalisierte Golang-Datenstrukturinstanzen als Werte zu speichern. Um mit Daten im Kettencode zu arbeiten, müssen Sie nach dem Lesen aus dem Status das Byte-Array entfernen.
Um über das Auto aufzuzeichnen, verwenden wir die folgenden Attribute:
- Kennung (Autonummer)
- Automodell
- Informationen zum Fahrzeughalter
- Informationen zur Datenänderungszeit
Um Daten in den Kettencode zu übertragen, erstellen Sie eine separate Struktur, die nur die Felder enthält, die von außerhalb des Kettencodes stammen:
Mit Schlüsseln arbeiten
Datensatzschlüssel in einem intelligenten Vertragsstatus sind eine Zeichenfolge. Es unterstützt auch die Möglichkeit, zusammengesetzte Schlüssel zu erstellen, bei denen Teile des Schlüssels durch ein Null-Byte ( U + 0000 ) getrennt sind.
func CreateCompositeKey(objectType string, attributes []string) (string, error)
In CCKit können die Funktionen zum Arbeiten mit dem Status eines intelligenten Vertrags automatisch Schlüssel für Datensätze erstellen, wenn die übertragenen Strukturen die Keyer- Schnittstelle unterstützen
Um ein Auto aufzuzeichnen, lautet die Schlüsselgenerierungsfunktion wie folgt:
const CarEntity = `CAR`
Intelligente Vertragsfunktionsdeklaration (Routing)
In der Konstruktormethode des Kettencodes können wir die Funktionen des Kettencodes und ihre Argumente definieren. Der Autokennzeichen enthält 3 Funktionen
- carList gibt ein Array von Car-Strukturen zurück
- carGet akzeptiert eine Fahrzeugkennung und gibt eine Fahrzeugstruktur zurück
- carRegister akzeptiert eine serialisierte Instanz der CarPayload-Struktur und gibt das Registrierungsergebnis zurück. Der Zugriff auf diese Methode ist nur für den Eigentümer des Kettencodes möglich, der mithilfe der Middleware aus dem Eigentümerpaket gespeichert wird
func New() *router.Chaincode { r := router.New(`cars`)
Im obigen Beispiel wird die Chaincode- Struktur verwendet, in der die Verarbeitung der Methoden Init und Invoke an den Router delegiert wird:
package router import ( "github.com/hyperledger/fabric/core/chaincode/shim" "github.com/hyperledger/fabric/protos/peer" )
Die Verwendung eines Routers und der grundlegenden Chaincode-Struktur ermöglicht die Wiederverwendung von Handlerfunktionen. Um beispielsweise Chaincode zu implementieren, ohne den Zugriff auf die carRegister
Funktion zu carRegister
, reicht carRegister
aus, eine neue Konstruktormethode zu erstellen
Implementierung der Funktionen eines Smart Contract
Golang-Funktionen - Es gibt drei Arten von intelligenten Vertragsfunktionshandlern im CCKit- Router:
- StubHandlerFunc - Die Standard-Handler-Schnittstelle akzeptiert shim.ChaincodeStubInterface und gibt die Standardantwort Peer.Response zurück
- ContextHandlerFunc - nimmt einen Kontext und gibt peer.Response zurück
- HandlerFunc - akzeptiert den Kontext, gibt die Schnittstelle und den Fehler zurück. Ein Byte-Array kann zurückgegeben werden oder ein beliebiger Golang-Typ, der automatisch in ein Byte-Array konvertiert wird, basierend darauf, welche Peer.Response erstellt wird. Der Antwortstatus lautet je nach übergebenem Fehler shim.Ok oder shim.Error .
Argumente der im Router beschriebenen Kettencodefunktionen werden automatisch von Bytearrays in Zieldatentypen (eine Zeichenfolge oder eine CarPayload-Struktur) konvertiert.
Die Kettencodefunktion verwendet Statusmethoden, die das Extrahieren und Speichern von Daten in einen Kettencodestatus vereinfachen, indem automatisch Schlüssel erstellt und die übertragenen Daten in Arrays konvertiert werden Byte (im Bytecode wird ein Array von Bytes geschrieben)
Intelligente Vertragstests
- — , . BDD – Behavior Driven Development, .
, , - Ethereum ganache-cli truffle . golang - Mockstub.
, . .
Ginkgo , Go, go test
. gomega expect , , .
import ( "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" examplecert "github.com/s7techlab/cckit/examples/cert" "github.com/s7techlab/cckit/extensions/owner" "github.com/s7techlab/cckit/identity" "github.com/s7techlab/cckit/state" testcc "github.com/s7techlab/cckit/testing" expectcc "github.com/s7techlab/cckit/testing/expect" ) func TestCars(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Cars Suite") }
, CarPayload :
var Payloads = []*Car{{ Id: `A777MP77`, Title: `VAZ`, Owner: `victor`, }, { Id: `O888OO77`, Title: `YOMOBIL`, Owner: `alexander`, }, { Id: `O222OO177`, Title: `Lambo`, Owner: `hodl`, }}
MockStub Cars.
Weil cars , .
BeforeSuite Car authority Init . , Cars Init Init , .
BeforeSuite(func() {
. , CarRegister , .
It("Allow authority to add information about car", func() {
:
It("Disallow authority to add duplicate information about car", func() { expectcc.ResponseError( cc.From(actors[`authority`]).Invoke(`carRegister`, Payloads[0]), state.ErrKeyAlreadyExists)
Fazit
- HLF Go, Java, JavaScript, , , - (Solidity) / -. / .
HLF , , ( .). Hypeledger Fabric , .. .