Fabric: Deployment and execution of chaincode

Hyperledger Fabric:V2.5.4

write first

Reference for using Fabric to build a custom network:https://blog.csdn.net/yeshang_lady/article/details/134113296
Using Fabric Reference for creating an application channel:https://blog.csdn.net/yeshang_lady/article/details/134668458
Next, we will introduce how to create an application channel in a customized network Deploy and execute chaincode on the channel.

1 Chaincode deployment

The deployment of chain code in Fabric generally includes the following steps: writing chain code->packaging chain code->installing chain code->instantiating chain code->deploying chain code, etc. The following steps will be introduced one by one.

1.1 Write chain code

After creating the network and application channels, go back to the finance_network directory to create the chaincode directoryusersChaincode. Then create a chaincode file under the chaincode directoryusersChaincode. The code is as follows (the code in this file is written using Constructed using the chaincode example in ):asset-transfer.gotest-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)
	}
}

Then use commands such asgo mod in the chaincode directory to initialize the module. Specifically include the following:

#先进入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

Tips: The following points need to be noted

  • First of all, when generating the go.mod file, the go language version is automatically specified as the go language version number installed in the current environment. For examplego 1.21.3. But the go language version number in go.mod should consist of two numbers separated by dots, such as 1.13, 1.14, etc.
  • Secondly,go.modThe go language version in the file must also consider the compatible version of the current third-party package here.
  • Again,go.mod the file must be modified and the go mod tidy command must be run to regeneratego.sum the file.
  • Finally, if you encounter the following problems when installing the chain code, you need to go back and modify it< /span>), and then regenerate (refer to file to file. Here you need to change the go language version in the also needs to repackage the chain code. For convenience, it is best to modify thefile in advance. invalid go version 1.21.3: must match format 1.23go.modgo.modgo 1.17fabric-samplesgo.sumgo.modInsert image description here
  • In addition, if you do not execute the GO111MODULE=on go mod vendor command, you will encounter a timeout problem during the subsequent installation of the chain code :Error: chaincode install failed with status: 500 ... error sending: timeout expired while executing transaction.
    Insert image description here

1.2 Packaging chain code

Packaging chaincode refers to packaging the chaincode file into a file in tar format. You can use the peer lifecycle chaincode package command. The specific execution command is as follows:

#先使用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

wherebasic is the chain code name. After the code is executed, you will see the file in the finance_network directory. Tips: The peer lifecycle chaincode package command only packages the chaincode into a tar format file. This process does not require interaction with specific peer nodes, so the execution of this command does not require binding the node in advance. . basic.tar.gz

1.3 Install chaincode

Installing the chain code is mainly responsible for deploying the chain code to each Peer node that needs to execute the chain code. Install the chain code to the local file system of the Peer node by calling the peer lifecycle chaincode install command of the Peer node. The following only describes the chain code installation process using the peer0.org1.finance.com node. The details are as follows:

#先设置环境变量将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

The results are as follows:
Insert image description here
You can use peer lifecycle chaincode queryinstalled to view the chain code that has been installed on the peer node. The details are as follows:
Insert image description here
In addition, the chain code is also installed on peer0.org2.finance.com, and the installation steps are omitted here. Tips: Although 3 peer nodes are created in the fabric_test network, the chain code does not necessarily need to be installed on all peer nodes.

1.4 Instantiate chaincode

  • Use the peer lifecycle chaincode approveformyorg command to complete the organization's approval of the chaincode deployment. Assume that both organizations need to agree on the deployment of chaincode. Here we take Org1 as an example. The specific code is as follows:
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} 

The result is as follows:
Insert image description here

  • Use the peer lifecycle chaincode checkcommitreadiness command to check the commit readiness of the chaincode definition. The specific commands are as follows:
peer lifecycle chaincode checkcommitreadiness --channelID channel1 --name basic --version 1.0 --sequence 1 

The execution results are as follows:
Insert image description here

  • Use the peer lifecycle chaincode commit command to submit the transaction defined by the chaincode. The command is as follows:
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"

The code execution result is as follows:
Insert image description here
You can use the following code to determine whether the submission is successful. The details are as follows:

peer lifecycly chaincode querycommitted -C channel1 -n basic

The execution result is as follows:
Insert image description here
At this point, the instantiation of the chain code has been completed. You can usedocker ps -a to see the container information of the chaincode. The details are as follows:
Insert image description here

2 Chaincode execution

Regarding the execution of chain code, only two commands are introduced here.

  • peer chaincode invoke: The chain code can be made to execute customized business logic and change the status in the blockchain ledger. Examples are as follows:
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"]}'

The execution results are as follows:
Insert image description here

  • peer chaincode query: Data can be obtained from the blockchain ledger without any status updates to the ledger.
peer chaincode query -C channel -n basic -c '{
    
    "Args":["GetAllAssets

The execution results are as follows:
Insert image description here
In order to illustrate thatpeer chaincode query has not modified the ledger, execute the following two commands, as follows:

#删除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"]}'

The result is as follows:
Insert image description here

Guess you like

Origin blog.csdn.net/yeshang_lady/article/details/134801201