• 【区块链技术与应用】(八)


    https://blog.csdn.net/lakersssss24/article/details/125762826?spm=1001.2014.3001.5501
    https://blog.csdn.net/lakersssss24/article/details/126434147
    https://blog.csdn.net/lakersssss24/article/details/126671408?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-3-126671408-blog-126434147.pc_relevant_3mothn_strategy_and_data_recovery&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-3-126671408-blog-126434147.pc_relevant_3mothn_strategy_and_data_recovery&utm_relevant_index=4

    提前准备

    在这里插入图片描述

    sudo apt-get update  更新源 
    sudo apt-get install ssh 安装远程客户端
    sudo apt-get install curl 安装命令行工具
    sudo apt-get install git 安装git
    sudo apt-get install gcc 安装gcc
    sudo apt-get install vim 安装vim文件编辑器
    sudo apt-get install make 安装make
    sudo apt-get install net-tools 安装网络工具
    sudo apt-get install net-tools  安装mousepad 类似于windows的记事本
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    ./bootstrap.sh
    
    • 1

    https://teach.imcn.me/y2020/1146.html

    couchDB安装 https://blog.csdn.net/TU_Dresden/article/details/126864418

    请添加图片描述

    实验一

    network

    ./network.sh up
    
    • 1

    请添加图片描述
    请添加图片描述

    ./network.sh up createChannel -s couchdb
    
    • 1

    请添加图片描述

    ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go
    
    • 1

    在这里插入图片描述
    在这里插入图片描述

    export PATH=${PWD}/../bin:$PATH
    export FABRIC_CFG_PATH=$PWD/../config/
    export CORE_PEER_TLS_ENABLED=true
    export CORE_PEER_LOCALMSPID="Org1MSP" 
    export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
    export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
    export CORE_PEER_ADDRESS=localhost:7051
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c '{"function":"InitLedger","Args":[""]}'
    
    • 1

    在这里插入图片描述
    restart

    ./network.sh up createChannel -ca -s couchdb
    
    
    
    • 1
    • 2
    • 3

    gin模板

    package main
     
    import (
    	"fmt"
    	"github.com/gin-gonic/gin"
    )
     
    type Stu struct {
    	Name string `form:"name"`
    	Id   string `form:"id"`
    	Age  string `form:"age"`
    }
     
    func main() {
    	r := gin.Default()
    	var stu Stu
    	r1 := r.Group("/fabric2.4")
    	r1.POST("/setstu", func(c *gin.Context) {
    		//var stu Stu
    		c.ShouldBind(&stu)
    		c.JSON(200, stu)
    		fmt.Println("stu:", stu)
    	})
    	r1.POST("/ok1", func(c *gin.Context) {
    		c.JSON(200, "ok1")
    	})
    	r.Run(":8080") // 监听并在 0.0.0.0:8080 上启动服务
     
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    链码的只要功能部分:

    package chaincode
     
    import (
    	"encoding/json"
    	"fmt"
     
    	"github.com/hyperledger/fabric-contract-api-go/contractapi"
    )
     
    // SmartContract provides functions for managing an Asset
    type SmartContract struct {
    	contractapi.Contract
    }
     
    // Asset describes basic details of what makes up a simple asset
    //Insert struct field in alphabetic order => to achieve determinism across languages
    // golang keeps the order when marshal to json but doesn't order automatically
    type Asset struct {
    	AppraisedValue int    `json:"AppraisedValue"`
    	Color          string `json:"Color"`
    	ID             string `json:"ID"`
    	Owner          string `json:"Owner"`
    	Size           int    `json:"Size"`
    }
     
    // InitLedger adds a base set of assets to the ledger
    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
    }
     
    // CreateAsset issues a new asset to the world state with given details.
    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)
    }
     
    // ReadAsset returns the asset stored in the world state with given id.
    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
    }
     
    // UpdateAsset updates an existing asset in the world state with provided parameters.
    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)
    	}
     
    	// overwriting original asset with new asset
    	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)
    }
     
    // DeleteAsset deletes an given asset from the world state.
    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)
    }
     
    // AssetExists returns true when asset with given ID exists in world state
    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
    }
     
    // TransferAsset updates the owner field of asset with given id in world state, and returns the old owner.
    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
    }
     
    // GetAllAssets returns all assets found in world state
    func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) {
    	// range query with empty string for startKey and endKey does an
    	// open-ended query of all assets in the chaincode namespace.
    	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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194

    查看虚拟机的IP和地址:

    ifconfig
    
    • 1

    gin框架

    package main
     
    import (
    	"bytes"
    	"crypto/x509"
    	"encoding/json"
    	"fmt"
    	"github.com/gin-gonic/gin"
    	"github.com/hyperledger/fabric-gateway/pkg/client"
    	"github.com/hyperledger/fabric-gateway/pkg/identity"
    	"google.golang.org/grpc"
    	"google.golang.org/grpc/credentials"
    	"io/ioutil"
    	"path"
    	"time"
    )
     
    const (
    	mspID         = "Org1MSP"
    	cryptoPath    = "./peerOrganizations/org1.example.com"
    	certPath      = cryptoPath + "/users/User1@org1.example.com/msp/signcerts/cert.pem"
    	keyPath       = cryptoPath + "/users/User1@org1.example.com/msp/keystore/"
    	tlsCertPath   = cryptoPath + "/peers/peer0.org1.example.com/tls/ca.crt"
    	peerEndpoint  = "192.168.136.130:7051"
    	gatewayPeer   = "peer0.org1.example.com"
    	channelName   = "mychannel"
    	chaincodeName = "basic"
    )
     
    type Asset struct {
    	AppraisedValue int    `form:"appraisedValue" json:"appraisedValue" `
    	Color          string `form:"color" json:"color"`
    	ID             string `form:"id" json:"id"`
    	Owner          string `form:"owner" json:"owner"`
    	Size           int    `form:"size" json:"size"`
    }
     
    func main() {
    	// The gRPC client connection should be shared by all Gateway connections to this endpoint
    	clientConnection := newGrpcConnection()
    	defer clientConnection.Close()
     
    	id := newIdentity()
    	sign := newSign()
     
    	// Create a Gateway connection for a specific client identity
    	gateway, err := client.Connect(
    		id,
    		client.WithSign(sign),
    		client.WithClientConnection(clientConnection),
    		// Default timeouts for different gRPC calls
    		client.WithEvaluateTimeout(5*time.Second),
    		client.WithEndorseTimeout(15*time.Second),
    		client.WithSubmitTimeout(5*time.Second),
    		client.WithCommitStatusTimeout(1*time.Minute),
    	)
    	if err != nil {
    		panic(err)
    	}
    	defer gateway.Close()
    	network := gateway.GetNetwork(channelName)
    	contract := network.GetContract(chaincodeName)
     
    	r := gin.Default()
    	r1 := r.Group("/fabric2.4")
    	r1.POST("/CreateAsset", func(c *gin.Context) {
    		var asset Asset
    		c.ShouldBind(&asset)
    		c.JSON(200, asset)
    		marshal, _ := json.Marshal(asset)
    		fmt.Println(string(marshal))
    		fmt.Println("asset:", asset)
    	})
    	r1.POST("/GetAllAssets", func(c *gin.Context) {
    		result := getAllAssets(contract)
    		c.JSON(200, result)
    	})
    	r.Run(":8080") // 监听并在 0.0.0.0:8080 上启动服务
     
    }
     
    // Evaluate a transaction to query ledger state.
    func getAllAssets(contract *client.Contract) string {
    	fmt.Println("Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger")
     
    	evaluateResult, err := contract.EvaluateTransaction("GetAllAssets")
    	if err != nil {
    		panic(fmt.Errorf("failed to evaluate transaction: %w", err))
    	}
    	result := formatJSON(evaluateResult)
     
    	fmt.Printf("*** Result:%s\n", result)
     
    	return string(evaluateResult)
    }
     
    // newGrpcConnection creates a gRPC connection to the Gateway server.
    func newGrpcConnection() *grpc.ClientConn {
    	certificate, err := loadCertificate(tlsCertPath)
    	if err != nil {
    		panic(err)
    	}
     
    	certPool := x509.NewCertPool()
    	certPool.AddCert(certificate)
    	transportCredentials := credentials.NewClientTLSFromCert(certPool, gatewayPeer)
     
    	connection, err := grpc.Dial(peerEndpoint, grpc.WithTransportCredentials(transportCredentials))
    	if err != nil {
    		panic(fmt.Errorf("failed to create gRPC connection: %w", err))
    	}
     
    	return connection
    }
     
    // newIdentity creates a client identity for this Gateway connection using an X.509 certificate.
    func newIdentity() *identity.X509Identity {
    	certificate, err := loadCertificate(certPath)
    	if err != nil {
    		panic(err)
    	}
     
    	id, err := identity.NewX509Identity(mspID, certificate)
    	if err != nil {
    		panic(err)
    	}
     
    	return id
    }
     
    func loadCertificate(filename string) (*x509.Certificate, error) {
    	certificatePEM, err := ioutil.ReadFile(filename)
    	if err != nil {
    		return nil, fmt.Errorf("failed to read certificate file: %w", err)
    	}
    	return identity.CertificateFromPEM(certificatePEM)
    }
     
    // newSign creates a function that generates a digital signature from a message digest using a private key.
    func newSign() identity.Sign {
    	files, err := ioutil.ReadDir(keyPath)
    	if err != nil {
    		panic(fmt.Errorf("failed to read private key directory: %w", err))
    	}
    	privateKeyPEM, err := ioutil.ReadFile(path.Join(keyPath, files[0].Name()))
     
    	if err != nil {
    		panic(fmt.Errorf("failed to read private key file: %w", err))
    	}
     
    	privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM)
    	if err != nil {
    		panic(err)
    	}
     
    	sign, err := identity.NewPrivateKeySign(privateKey)
    	if err != nil {
    		panic(err)
    	}
     
    	return sign
    }
     
    // Format JSON data
    func formatJSON(data []byte) string {
    	var prettyJSON bytes.Buffer
    	if err := json.Indent(&prettyJSON, data, " ", ""); err != nil {
    		panic(fmt.Errorf("failed to parse JSON: %w", err))
    	}
    	return prettyJSON.String()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171

    在这里插入图片描述

    链码

    package chaincode
     
    import (
    	"encoding/json"
    	"fmt"
     
    	"github.com/hyperledger/fabric-contract-api-go/contractapi"
    )
     
    // SmartContract provides functions for managing an Asset
    type SmartContract struct {
    	contractapi.Contract
    }
     
    // Asset describes basic details of what makes up a simple asset
    //Insert struct field in alphabetic order => to achieve determinism across languages
    // golang keeps the order when marshal to json but doesn't order automatically
    type Asset struct {
    	AppraisedValue int    `json:"AppraisedValue"`
    	Color          string `json:"Color"`
    	ID             string `json:"ID"`
    	Owner          string `json:"Owner"`
    	Size           int    `json:"Size"`
    }
     
    // InitLedger adds a base set of assets to the ledger
    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
    }
     
    // CreateAsset issues a new asset to the world state with given details.
    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)
    }
     
    // ReadAsset returns the asset stored in the world state with given id.
    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
    }
     
    // UpdateAsset updates an existing asset in the world state with provided parameters.
    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)
    	}
     
    	// overwriting original asset with new asset
    	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)
    }
     
    // DeleteAsset deletes an given asset from the world state.
    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)
    }
     
    // AssetExists returns true when asset with given ID exists in world state
    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
    }
     
    // TransferAsset updates the owner field of asset with given id in world state, and returns the old owner.
    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
    }
     
    // GetAllAssets returns all assets found in world state
    func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) {
    	// range query with empty string for startKey and endKey does an
    	// open-ended query of all assets in the chaincode namespace.
    	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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194

    postman

    在这里插入图片描述
    测试自家网站:
    在这里插入图片描述
    在这里插入图片描述

    本地查询:
    在这里插入图片描述
    在这里插入图片描述
    自己的github:
    在这里插入图片描述

    请添加图片描述

    请添加图片描述
    请添加图片描述
    请添加图片描述

    实验二

    gin

    package main
     
    import (
    	"bytes"
    	"crypto/x509"
    	"encoding/json"
    	"fmt"
    	"github.com/gin-gonic/gin"
    	"github.com/hyperledger/fabric-gateway/pkg/client"
    	"github.com/hyperledger/fabric-gateway/pkg/identity"
    	"google.golang.org/grpc"
    	"google.golang.org/grpc/credentials"
    	"io/ioutil"
    	"path"
    	"time"
    )
     
    const (
    	mspID         = "Org1MSP"
    	cryptoPath    = "./peerOrganizations/org1.example.com"
    	certPath      = cryptoPath + "/users/User1@org1.example.com/msp/signcerts/cert.pem"
    	keyPath       = cryptoPath + "/users/User1@org1.example.com/msp/keystore/"
    	tlsCertPath   = cryptoPath + "/peers/peer0.org1.example.com/tls/ca.crt"
    	peerEndpoint  = "192.168.136.130:7051"
    	gatewayPeer   = "peer0.org1.example.com"
    	channelName   = "mychannel"
    	chaincodeName = "basic"
    )
     
    type Asset struct {
    	AppraisedValue int    `form:"appraisedValue" json:"appraisedValue" `
    	Color          string `form:"color" json:"color"`
    	ID             string `form:"id" json:"id"`
    	Owner          string `form:"owner" json:"owner"`
    	Size           int    `form:"size" json:"size"`
    }
     
    func main() {
    	// The gRPC client connection should be shared by all Gateway connections to this endpoint
    	clientConnection := newGrpcConnection()
    	defer clientConnection.Close()
     
    	id := newIdentity()
    	sign := newSign()
     
    	// Create a Gateway connection for a specific client identity
    	gateway, err := client.Connect(
    		id,
    		client.WithSign(sign),
    		client.WithClientConnection(clientConnection),
    		// Default timeouts for different gRPC calls
    		client.WithEvaluateTimeout(5*time.Second),
    		client.WithEndorseTimeout(15*time.Second),
    		client.WithSubmitTimeout(5*time.Second),
    		client.WithCommitStatusTimeout(1*time.Minute),
    	)
    	if err != nil {
    		panic(err)
    	}
    	defer gateway.Close()
    	network := gateway.GetNetwork(channelName)
    	contract := network.GetContract(chaincodeName)
     
    	r := gin.Default()
    	r1 := r.Group("/fabric2.4.2")
    	r1.POST("/Init", func(c *gin.Context) {
    		initLedger(contract)
    		c.JSON(200, "init ok!")
    	})
    	r.Run(":8080") // 监听并在 0.0.0.0:8080 上启动服务
     
    }
     
    // Evaluate a transaction to query ledger state.
    func getAllAssets(contract *client.Contract) string {
    	fmt.Println("Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger")
     
    	evaluateResult, err := contract.EvaluateTransaction("GetAllAssets")
    	if err != nil {
    		panic(fmt.Errorf("failed to evaluate transaction: %w", err))
    	}
    	result := formatJSON(evaluateResult)
     
    	fmt.Printf("*** Result:%s\n", result)
     
    	return string(evaluateResult)
    }
     
    // newGrpcConnection creates a gRPC connection to the Gateway server.
    func newGrpcConnection() *grpc.ClientConn {
    	certificate, err := loadCertificate(tlsCertPath)
    	if err != nil {
    		panic(err)
    	}
     
    	certPool := x509.NewCertPool()
    	certPool.AddCert(certificate)
    	transportCredentials := credentials.NewClientTLSFromCert(certPool, gatewayPeer)
     
    	connection, err := grpc.Dial(peerEndpoint, grpc.WithTransportCredentials(transportCredentials))
    	if err != nil {
    		panic(fmt.Errorf("failed to create gRPC connection: %w", err))
    	}
     
    	return connection
    }
     
    // newIdentity creates a client identity for this Gateway connection using an X.509 certificate.
    func newIdentity() *identity.X509Identity {
    	certificate, err := loadCertificate(certPath)
    	if err != nil {
    		panic(err)
    	}
     
    	id, err := identity.NewX509Identity(mspID, certificate)
    	if err != nil {
    		panic(err)
    	}
     
    	return id
    }
     
    func loadCertificate(filename string) (*x509.Certificate, error) {
    	certificatePEM, err := ioutil.ReadFile(filename)
    	if err != nil {
    		return nil, fmt.Errorf("failed to read certificate file: %w", err)
    	}
    	return identity.CertificateFromPEM(certificatePEM)
    }
     
    // newSign creates a function that generates a digital signature from a message digest using a private key.
    func newSign() identity.Sign {
    	files, err := ioutil.ReadDir(keyPath)
    	if err != nil {
    		panic(fmt.Errorf("failed to read private key directory: %w", err))
    	}
    	privateKeyPEM, err := ioutil.ReadFile(path.Join(keyPath, files[0].Name()))
     
    	if err != nil {
    		panic(fmt.Errorf("failed to read private key file: %w", err))
    	}
     
    	privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM)
    	if err != nil {
    		panic(err)
    	}
     
    	sign, err := identity.NewPrivateKeySign(privateKey)
    	if err != nil {
    		panic(err)
    	}
     
    	return sign
    }
     
    // Format JSON data
    func formatJSON(data []byte) string {
    	var prettyJSON bytes.Buffer
    	if err := json.Indent(&prettyJSON, data, " ", ""); err != nil {
    		panic(fmt.Errorf("failed to parse JSON: %w", err))
    	}
    	return prettyJSON.String()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163

    New asset部分:
    把下图代码:
    在这里插入图片描述
    改为这个:

    r1.POST("/CreateAsset", func(c *gin.Context) {
    		var asset Asset
    		c.ShouldBind(&asset)
    		c.JSON(200, asset)
    		marshal, _ := json.Marshal(asset)
    		CreateAsset(contract, asset)
    		fmt.Println("存入成功!存入的数据是:", string(marshal))
    		//fmt.Println("asset:", asset)
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    函数:

    func CreateAsset(contract *client.Contract, asset Asset) string {
    	evaluateResult, err := contract.SubmitTransaction("CreateAsset", asset.ID, asset.Color, strconv.Itoa(asset.Size), asset.Owner, strconv.Itoa(asset.AppraisedValue))
    	if err != nil {
    		panic(fmt.Errorf("failed to evaluate transaction: %w", err))
    	}
    	result := formatJSON(evaluateResult)
     
    	fmt.Printf("*** Result:%s\n", result)
     
    	return string(evaluateResult)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述
    在这里插入图片描述

    总结

    本次实验内容内容不多,难度颇大。
    其一在于作者默认搭好框架,所以需要按照前文做出适配。
    其二是网络搭好之后的查询,如果看了前文,可以知道作者是修改了

    https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-basic

    部分的代码,也就是本文的gin框架部分。修改也很多,
    在这里插入图片描述
    然后就是代码,代码在我这里经常报错,然后为了解决一个bug往往会搞出更多的问题,尤其是网络接口的占用,就在写文档的现在,我的7051端口莫名被占用了,为了更好完成期末任务,决定找一个正确而清晰的文档从头开始配置。(很大的原因是这几次作业下来整个fabric文件夹臃肿不堪,fabric-samples就有好几个,隔着几周时间回去看,有能运行的,也有当初是坑,后来没删的,总之,归零重启更有效)

    在做两个实验之前,我先按照作者的思路配置了环境,主要是启动网络。
    其次是一种很新的工具,postman,现在还没有完全摸清这个软件的用途,目前仅做查询网址用途。

    第二个查询部分没有把assets查出来,可能是某个方面出了bug,之后会重新启用虚拟机,然后从头开始做一遍。

    请添加图片描述

  • 相关阅读:
    HCIP(第十四天)
    APT 组织 Kimsuky 瞄准大学研究人员
    企业架构LNMP学习笔记28
    网络路由详解
    中科柏诚获“专精特新”称号,把一件事做到极致就是价值
    03 矩阵与线性变换
    Find My技术|苹果Find My网络带来的好处
    windows殺死端口
    10-26 maven配置
    Java反射--师承韩顺平
  • 原文地址:https://blog.csdn.net/Algernon98/article/details/128009665