Hyperledger Fabric:V2.5.4
schreibe zuerst
Referenz für die Verwendung von Fabric zum Aufbau eines benutzerdefinierten Netzwerks:https://blog.csdn.net/yeshang_lady/article/details/134113296
Verwenden von Fabric Reference zum Erstellen eines Anwendungskanals:https://blog.csdn.net/yeshang_lady/article/details/134668458
Als Nächstes stellen wir vor, wie So erstellen Sie einen Anwendungskanal in einem benutzerdefinierten Netzwerk. Stellen Sie Chaincode auf dem Kanal bereit und führen Sie ihn aus.
1 Chaincode-Bereitstellung
Die Bereitstellung von Kettencode in Fabric umfasst im Allgemeinen die folgenden Schritte: Kettencode schreiben – Kettencode verpacken – Kettencode installieren – Kettencode instanziieren – Kettencode bereitstellen usw. Die folgenden Schritte werden nacheinander eingeführt.
1.1 Kettencode schreiben
Gehen Sie nach dem Erstellen der Netzwerk- und Anwendungskanäle zurück zum Verzeichnis finance_network
, um das Chaincode-Verzeichnis zu erstellenusersChaincode
. Erstellen Sie dann eine Chaincode-Datei im Chaincode-VerzeichnisusersChaincode
. Der Code lautet wie folgt (der Code in dieser Datei wird mit Konstruiert unter Verwendung des Chaincode-Beispiels in ):asset-transfer.go
test-network
package main
import (
"encoding/json"
"fmt"
"log"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
type SmartContract struct {
contractapi.Contract
}
type Asset struct {
AppraisedValue int `json:"AppraisedValue"`
Color string `json:"Color"`
ID string `json:"ID"`
Owner string `json:"Owner"`
Size int `json:"Size"`
}
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
assets := []Asset{
{
ID: "asset1", Color: "blue", Size: 5, Owner: "Tomoko", AppraisedValue: 300},
{
ID: "asset2", Color: "red", Size: 5, Owner: "Brad", AppraisedValue: 400},
{
ID: "asset3", Color: "green", Size: 10, Owner: "Jin Soo", AppraisedValue: 500},
{
ID: "asset4", Color: "yellow", Size: 10, Owner: "Max", AppraisedValue: 600},
{
ID: "asset5", Color: "black", Size: 15, Owner: "Adriana", AppraisedValue: 700},
{
ID: "asset6", Color: "white", Size: 15, Owner: "Michel", AppraisedValue: 800},
}
for _, asset := range assets {
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
err = ctx.GetStub().PutState(asset.ID, assetJSON)
if err != nil {
return fmt.Errorf("failed to put to world state. %v", err)
}
}
return nil
}
func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error {
exists, err := s.AssetExists(ctx, id)
if err != nil {
return err
}
if exists {
return fmt.Errorf("the asset %s already exists", id)
}
asset := Asset{
ID: id,
Color: color,
Size: size,
Owner: owner,
AppraisedValue: appraisedValue,
}
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
return ctx.GetStub().PutState(id, assetJSON)
}
func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) {
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return nil, fmt.Errorf("failed to read from world state: %v", err)
}
if assetJSON == nil {
return nil, fmt.Errorf("the asset %s does not exist", id)
}
var asset Asset
err = json.Unmarshal(assetJSON, &asset)
if err != nil {
return nil, err
}
return &asset, nil
}
func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error {
exists, err := s.AssetExists(ctx, id)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("the asset %s does not exist", id)
}
asset := Asset{
ID: id,
Color: color,
Size: size,
Owner: owner,
AppraisedValue: appraisedValue,
}
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
return ctx.GetStub().PutState(id, assetJSON)
}
func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error {
exists, err := s.AssetExists(ctx, id)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("the asset %s does not exist", id)
}
return ctx.GetStub().DelState(id)
}
func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return false, fmt.Errorf("failed to read from world state: %v", err)
}
return assetJSON != nil, nil
}
func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) (string, error) {
asset, err := s.ReadAsset(ctx, id)
if err != nil {
return "", err
}
oldOwner := asset.Owner
asset.Owner = newOwner
assetJSON, err := json.Marshal(asset)
if err != nil {
return "", err
}
err = ctx.GetStub().PutState(id, assetJSON)
if err != nil {
return "", err
}
return oldOwner, nil
}
func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) {
resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
if err != nil {
return nil, err
}
defer resultsIterator.Close()
var assets []*Asset
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}
var asset Asset
err = json.Unmarshal(queryResponse.Value, &asset)
if err != nil {
return nil, err
}
assets = append(assets, &asset)
}
return assets, nil
}
func main() {
assetChaincode, err := contractapi.NewChaincode(&SmartContract{
})
if err != nil {
log.Panicf("Error creating asset-transfer-basic chaincode: %v", err)
}
if err := assetChaincode.Start(); err != nil {
log.Panicf("Error starting asset-transfer-basic chaincode: %v", err)
}
}
Verwenden Sie dann Befehle wiego mod
im Chaincode-Verzeichnis, um das Modul zu initialisieren. Fügen Sie insbesondere Folgendes hinzu:
#先进入usersChaincode目录下
go mod init
sudo chmod -R 777 go.mod
#下载链码中的需要的模块信息
go get github.com/hyperledger/fabric-contract-api-go/contractapi
sudo chmod -R 777 go.sum
#将项目的依赖库复制都vendor目录中去
GO111MODULE=on go mod vendor
Tipps: Folgende Punkte sind zu beachten
- Zunächst wird beim Generieren der
go.mod
-Datei die Go-Sprachversion automatisch als die in der aktuellen Umgebung installierte Go-Sprachversionsnummer angegeben. Zum Beispielgo 1.21.3
. Die Versionsnummer der Go-Sprache ingo.mod
sollte jedoch aus zwei durch Punkte getrennten Zahlen bestehen, z. B. 1.13, 1.14 usw. - Zweitens
go.mod
Die Go-Sprachversion in der Datei muss hier auch die kompatible Version des aktuellen Drittanbieterpakets berücksichtigen. - Erneut
go.mod
muss die Datei geändert werden und der Befehlgo mod tidy
muss ausgeführt werden, um die Datei neu zu generierengo.sum
. - Wenn bei der Installation des Kettencodes schließlich die folgenden Probleme auftreten, müssen Sie fortfahren zurück und ändern Sie die Datei. Hier müssen Sie die Go-Sprachversion in der Datei in ändern (siehe ) und dann muss auch den Kettencode neu packen. Der Einfachheit halber ist es am besten, dieDatei im Voraus zu ändern.
invalid go version 1.21.3: must match format 1.23
go.mod
go.mod
go 1.17
fabric-samples
go.sum
go.mod
- Wenn Sie außerdem den Befehl
GO111MODULE=on go mod vendor
nicht ausführen, tritt bei der nachfolgenden Installation des KettencodesError: chaincode install failed with status: 500 ... error sending: timeout expired while executing transaction
. :
1.2 Verpackungskettencode
Das Packen von Chaincode bezieht sich auf das Packen der Chaincode-Datei in eine Datei im TAR-Format. Sie können den Befehl peer lifecycle chaincode package
verwenden. Der spezifische Ausführungsbefehl lautet wie folgt:
#先使用cd命令跳转到finance_network目录下
export FABRIC_CFG_PATH=$PWD/config
#basic即为链码的名字
peer lifecycle chaincode package basic.tar.gz --path usersChaincode --lang "golang" --label basic_1.0.1
wobeibasic
der Kettencodename ist. Nachdem der Code ausgeführt wurde, sehen Sie die Datei im Verzeichnis finance_network
. Tipps: Der Befehl „peer lifecycle chaincode package“ packt den Chaincode nur in eine TAR-Formatdatei. Dieser Prozess erfordert keine Interaktion mit bestimmten Peer-Knoten, sodass die Ausführung dieses Befehls keine Bindung des Knotens erfordert im Voraus. . basic.tar.gz
1.3 Chaincode installieren
Die Installation des Kettencodes ist hauptsächlich für die Bereitstellung des Kettencodes auf jedem Peer-Knoten verantwortlich, der den Kettencode ausführen muss. Installieren Sie den Kettencode im lokalen Dateisystem des Peer-Knotens, indem Sie den Befehl peer lifecycle chaincode install
des Peer-Knotens aufrufen. Im Folgenden wird nur der Kettencode-Installationsprozess unter Verwendung des peer0.org1.finance.com
-Knotens beschrieben. Die Details lauten wie folgt:
#先设置环境变量将peer CLI绑定到peer0.org1.finance.com节点上
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PWD/organizations/peerOrganizations/org1.finance.com/peers/peer0.org1.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=$PWD/organizations/peerOrganizations/org1.finance.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:7051
export FABRIC_CFG_PATH=$PWD/config
# 安装链码
peer lifecycle chaincode install basic.tar.gz
Die Ergebnisse lauten wie folgt:
Sie können peer lifecycle chaincode queryinstalled
verwenden, um den Kettencode anzuzeigen, der auf dem Peer-Knoten installiert wurde. Die Details lauten wie folgt:
Darüber hinaus wird der Kettencode auch auf peer0.org2.finance.com
installiert, und die Installationsschritte werden hier weggelassen. Tipps: Obwohl im fabric_test-Netzwerk 3 Peer-Knoten erstellt werden, muss der Kettencode nicht unbedingt auf allen Peer-Knoten installiert werden.
1.4 Kettencode instanziieren
- Verwenden Sie den Befehl
peer lifecycle chaincode approveformyorg
, um die Genehmigung der Chaincode-Bereitstellung durch die Organisation abzuschließen. Gehen Sie davon aus, dass beide Organisationen sich auf die Bereitstellung von Chaincode einigen müssen. Hier nehmen wirOrg1
als Beispiel. Der spezifische Code lautet wie folgt:
export ORDERER_CA=$PWD/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/msp/tlscacerts/tlsca.finance.com-cert.pem
export PACKAGE_ID=$(peer lifecycle chaincode calculatepackageid basic.tar.gz)
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.finance.com --tls --cafile "$ORDERER_CA" --channelID channel1 --name basic --version 1.0 --sequence 1 --package-id ${PACKAGE_ID}
Das Ergebnis ist wie folgt:
- Verwenden Sie den Befehl
peer lifecycle chaincode checkcommitreadiness
, um die Commit-Bereitschaft der Chaincode-Definition zu überprüfen. Die spezifischen Befehle lauten wie folgt:
peer lifecycle chaincode checkcommitreadiness --channelID channel1 --name basic --version 1.0 --sequence 1
Die Ausführungsergebnisse sind wie folgt:
- Verwenden Sie den Befehl
peer lifecycle chaincode commit
, um die durch den Kettencode definierte Transaktion zu übermitteln. Der Befehl lautet wie folgt:
peer lifecycle chaincode commit -o localhost:7050 --orderdeTLSHostnameOverride orderer.finance.com --tls --cafile "$ORDERER_CA" --channelID channel1 --name basic --version 1.0 --sequence 1 --peerAddresses localhost:7051 --tlsRootCertFiles "${
PWD}/organizations/peerOrganizations/org1.finance.com/peers/peer0.org1.finance.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${
PWD}/organizations/peerOrganizations/org2.finance.com/peers/peer0.org2.finance.com/tls/ca.crt"
Das Ergebnis der Codeausführung lautet wie folgt:
Mit dem folgenden Code können Sie feststellen, ob die Übermittlung erfolgreich war. Die Details lauten wie folgt:
peer lifecycly chaincode querycommitted -C channel1 -n basic
Das Ausführungsergebnis ist wie folgt:
Zu diesem Zeitpunkt ist die Instanziierung des Kettencodes abgeschlossen. Mitdocker ps -a
können Sie die Containerinformationen des Chaincodes anzeigen. Die Details lauten wie folgt:
2 Chaincode-Ausführung
Bezüglich der Ausführung von Kettencode werden hier nur zwei Befehle vorgestellt.
peer chaincode invoke
: Der Kettencode kann so gestaltet werden, dass er eine benutzerdefinierte Geschäftslogik ausführt und den Status im Blockchain-Ledger ändert. Beispiele sind wie folgt:
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.finance.com --tls --cafile "${
PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/msp/tlscacerts/tlsca.finance.com-cert.pem" -C channel1 -n basic --peerAddresses localhost:7051 --tlsRootCertFiles "${
PWD}/organizations/peerOrganizations/org1.finance.com/peers/peer0.org1.finance.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${
PWD}/organizations/peerOrganizations/org2.finance.com/peers/peer0.org2.finance.com/tls/ca.crt" -c '{"Args":["InitLedger"]}'
Die Ausführungsergebnisse sind wie folgt:
peer chaincode query
: Daten können aus dem Blockchain-Ledger abgerufen werden, ohne dass Statusaktualisierungen des Ledgers erforderlich sind.
peer chaincode query -C channel -n basic -c '{
"Args":["GetAllAssets
Die Ausführungsergebnisse lauten wie folgt:
Um zu veranschaulichen, dasspeer chaincode query
das Hauptbuch nicht geändert hat, führen Sie die folgenden zwei Befehle wie folgt aus:
#删除id为asset6的记录
peer chaincode query -C channel1 -n basic -c '{"Args":["DeleteAsset","asset6"]}'
#读取id为asset6的记录
peer chaincode query -C channel1 -n basic -c '{"Args":["ReadAsset","asset6"]}'
Das Ergebnis ist wie folgt: