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

news2024/9/22 21:28:37

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的记事本
./bootstrap.sh

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

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

请添加图片描述

实验一

network

./network.sh up

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

./network.sh up createChannel -s couchdb

请添加图片描述

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

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

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
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":[""]}'

在这里插入图片描述
restart

./network.sh up createChannel -ca -s couchdb


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 上启动服务
 
}

链码的只要功能部分:

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
}

查看虚拟机的IP和地址:

ifconfig

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()
}

在这里插入图片描述

链码

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
}

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()
}

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)
	})

函数:

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)
}

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

总结

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

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

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

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

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

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/32812.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]java毕业设计医院仪器设备管理系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

cubeIDE开发, stm32的OLED点亮及字符显示设计(基于SPI通信)

一、SPI 通信技术 显示屏(LCD、OLED)接口一般有I2C、SPI、UART、RGB、LVDS、MIPI、EDP和DP等。一般3.5寸以下的小尺寸LCD屏,显示数据量比较少,普遍采用低速串口,如I2C、SPI、UART。SPI(Serial Peripheral I…

通用后台管理系统前端界面Ⅹ——前端数据表格的删除、查找

删除操作 1、拿到id或者行数据对象 2、查看后端接口方法,写api方法,将操作连接上后端 后端请求操作成功,但是前端数据表格未更新,最简单的一种方法数据删除后要重新获取数据》 依旧显示成功,但是前端数据表格未变化&…

Bert and its family

Bert没有办法一次性读入特别长的文本的问题。自注意力机制非常消耗时间和空间。 概率值最大取argmax,对应的下标 整体全部更新,所有参数都更新,比固定住pre-trained要好很多。 不做预训练,loss下降比较慢,收敛比较慢&a…

BIM在工程中的20种典型功能

1、BIM模型维护 根据项目建设进度建立和维护BIM模型,实质是使用BIM平台汇总各项目团队所有的建筑工程信息,消除项目中的信息孤岛,并且将得到的信息结合三维模型进行整理和储存,以备项目全过程中项目各相关利益方随时共享。 由于…

Java 微信关注/取消关注事件

Java 微信关注/取消关注事件一、需求、思路二、文档、配置配置步骤1配置步骤2三、代码1、引入依赖包2、controller3、封装消息对象4、service、解密5、工具包一、需求、思路 需求:用户订阅/取消订阅公众号时接收消息并保存到数据库中以便后续功能的处理。 思路&…

【分类-SVDD】基于支持向量数据描述 (SVDD) 的多类分类算法附matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 更多Matlab仿真内容点击👇 智能优化算法 …

机器学习-回归模型相关重要知识点

目录01 线性回归的假设是什么?02 什么是残差,它如何用于评估回归模型?03 如何区分线性回归模型和非线性回归模型?04 什么是多重共线性,它如何影响模型性能?05 异常值如何影响线性回归模型的性能&#xff1f…

Springboot Security 前后端分离模式自由接口最小工作模型

但凡讲解Springboot Security的教程,都是根据其本身的定义,前后端整合在一起,登录采用form或者basic。我们现在的很多项目,前后端分离,form登录已经不适用了。很多程序的架构要求所有的接口都采用application/json方式…

RabbitMQ顺序性、可靠性、重复消费、消息堆积解决方案

RabbitMQ顺序性、可靠性(消息丢失)、重复消费、消息堆积解决方案 顺序性 RabbitMQ使用过程中,有些业务场景需要我们保证顺序消费,例如:业务上产生三条消息,分别是对数据的增加、修改、删除操作&#xff0…

【Java八股文总结】之Linux常用指令

文章目录Linux简介一、Linux目录结构二、Linux常用指令Linux简介 一、Linux目录结构 bin(binaries):存放二进制可执行文件。 sbin(super user binaries):存放二进制可执行文件,只有root才能访…

怎么把图片转换成表格?分享三个简单方法给你

你们是否在工作的时候会遇到这样的情况:收到同事发来的一张表格图片,需要你进行汇总登记,通常这种时候,你们都会怎么做呢?是根据图片的内容,手动输入制作成一份表格吗?虽然这样子可以进行表格的…

c++ 旅行商问题(动态规划)

目录一、旅行商问题简介旅行商问题问题概述问题由来二、基本思路三、实现1、状态压缩2、状态转移四、代码复杂度分析一、旅行商问题简介 旅行商问题 TSP,即旅行商问题,又称TSP问题(Traveling Salesman Problem),是数学…

网络编程基础知识

文章目录1、网络概念2、协议3、网络分层4、网络传输流程5、端口号1、网络概念 先有计算机还是先有网络呢? 答案是先有计算机,为了数据研究和沟通的需求产生的网络,网络的产生是为了提升效率的。 那什么是网络呢? 网络指的是网络协…

实现一个自定义的vue脚手架

开发背景 博客很久没有更新了, 今天更新一个好玩的,等我将vue3的东西彻底搞明白我会更新一个vue3的系列,到时候会更新稍微勤一点,在使用vuecli的时候发现他的脚手架很有意思,用了几年了,但是一直没有好好研…

HTML CSS 网页设计作业「动漫小站」

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置,有div的样式格局,这个实例比较全面,有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 文章目录一、网页介绍一…

Neon intrinsics 简明教程

文章目录前言SIMD & NEONNEON intrinsicsNEON intrinsics 学习资料寄存器向量数据类型NENO intrinsics 命名方式NEON Intrinsics 查询三种处理方式:Long/Wide/NarrowNENO intrinsics 手册Addition 向量加法Vector add: vadd{q}_type. Vr[i]:Va[i]Vb[i]Vector lo…

Python-Flask 模型介绍和配置(6)

Flask数据模型和连接数据库一、安装二、配置数据库连接、创建模型类三、使用命令创建数据库表四、以注册为例flask是基于MTV的结构,其中M指的就是模型,即数据模型,在项目中对应的是数据库。flask与数据库建立联系有很多方法,但一般…

《安富莱嵌入式周报》第292期:树莓派单片机100M双通道示波器开源,MDK5.38发布,万用表单芯片解决方案,8通道±25V模拟前端芯片,开源贴片拾取电机板

往期周报汇总地址:嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 更新视频教程: GUI综合实战视频教程第3期:GUIX Studio一条龙设计主界面,底栏和…

【计算机毕业设计】32.学生宿舍管理系统源码

一、系统截图(需要演示视频可以私聊) 摘 要 随着计算机技术的飞速发展及其在宿舍管理方面应用的普及,利用计算机实现对学生宿舍管理势在必行。经过实际的需求分析,本系统采用Eclipse作为开发工具,采用功能强大的MySQL…