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

本文介绍了三个Hyperledger Fabric区块链案例:资产转移、触发事件及链下数据存储,通过Go和Java代码展示,包括交易操作、事件发布与恢复,以及区块链数据持久化。

在这里插入图片描述

引言

本次任务相对顺利,因为是已经打包的案例。不过二三案例中不像案例一中有go的chaincode,执行需要花时间debug
在这里插入图片描述

案例链接:

https://pkg.go.dev/github.com/hyperledger/fabric-gateway/pkg/client#section-readme

案例一:资产转移基本示例

代码分析

资产转移基本示例演示:

  • 将客户端应用程序连接到 Fabric 区块链网络。
  • 提交智能合约交易以更新账本状态。
  • 评估智能合约交易以查询账本状态。
  • 处理事务调用中的错误。

https://blog.youkuaiyun.com/ling1998/article/details/127202209

链码启动

项目地址:

https://github.com/hyperledger/fabric-samples/blob/main/asset-transfer-basic/chaincode-go/assetTransfer.go

/*
SPDX-License-Identifier: Apache-2.0
*/

package main

import (
	"log"

	"github.com/hyperledger/fabric-contract-api-go/contractapi"
	"github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-go/chaincode"
)

func main() {
	assetChaincode, err := contractapi.NewChaincode(&chaincode.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)
	}
}
链码结构

asset-transfer-basic/chaincode-go/chaincode/smartcontract.go

type SmartContract struct {
	contractapi.Contract
}

完整代码

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
}

运行

创建测试网络和通道
./network.sh up createChannel -c mychannel -ca

在这里插入图片描述
请添加图片描述

部署实现其中一个智能合约
# To deploy the TypeScript chaincode implementation
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-typescript/ -ccl typescript

# To deploy the Go chaincode implementation
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go/ -ccl go

# To deploy the Java chaincode implementation
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-java/ -ccl java

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

运行应用程序
# To run the Typescript sample application
cd application-gateway-typescript
npm install
npm start

# To run the Go sample application
cd application-gateway-go
go run .

# To run the Java sample application
cd application-gateway-java
./gradlew run

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

结束

./network.sh down

案例二:资产转移事件示例

资产转移事件示例演示:

从智能合约交易函数发出链码事件。
在客户端应用程序中接收链码事件。
在客户端应用程序中重放以前的链码事件。

运行

创建测试网络和通道
./network.sh up createChannel -c mychannel -ca

在这里插入图片描述

部署实现其中一个智能合约
# To deploy the JavaScript chaincode implementation
./network.sh deployCC -ccn events -ccp ../asset-transfer-events/chaincode-javascript/ -ccl javascript -ccep "OR('Org1MSP.peer','Org2MSP.peer')"

# To deploy the Java chaincode implementation
./network.sh deployCC -ccn events -ccp ../asset-transfer-events/chaincode-java/ -ccl java -ccep "OR('Org1MSP.peer','Org2MSP.peer')"

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

运行应用程序

(从文件夹)asset-transfer-events

# To run the Go sample application
cd application-gateway-go
go run .

# To run the Typescript sample application
cd application-gateway-typescript
npm install
npm start

# To run the Java sample application
cd application-gateway-java
./gradlew run

在这里插入图片描述

结束

回到test-network

./network.sh down

案例三:链下数据存储示例

链下数据存储示例演示:

  • 在客户端应用程序中接收块事件。
  • 使用检查指针在发生故障或应用程序重新启动后恢复事件侦听。
  • 从区块事件中提取账本更新,以构建链下数据存储。

运行

创建测试网络和通道
./network.sh up createChannel -c mychannel -ca

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

部署资产转移基本智能合约实现之一
# To deploy the TypeScript chaincode implementation
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-typescript/ -ccl typescript

# To deploy the Go chaincode implementation
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go/ -ccl go

# To deploy the Java chaincode implementation
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-java/ -ccl java

在这里插入图片描述

用一些资产填充账本,并使用事件来捕获账本更新

从文件夹)。off_chain_data

# To run the TypeScript sample application
cd application-typescript
npm install
npm start transact listen

# To run the Java sample application
cd application-java
./gradlew run --quiet --args='transact listen'
使用Control-C 中断侦听器进程
查看区块链的当前世界状态

off_chain_datastore.log

# To run the TypeScript sample application
cd application-typescript
npm --silent start getAllAssets

# To run the Java sample application
cd application-java
./gradlew run --quiet --args=getAllAssets

在这里插入图片描述

进行更多账本更新,然后观察侦听器恢复功能
# To run the TypeScript sample application
cd application-typescript
npm start transact
SIMULATED_FAILURE_COUNT=5 npm start listen
npm start listen

# To run the Java sample application
cd application-java
./gradlew run --quiet --args=transact
SIMULATED_FAILURE_COUNT=5 ./gradlew run --quiet --args=listen
./gradlew run --quiet --args=listen

请添加图片描述
在这里插入图片描述

总结

本周主要进行了三个案例的实战,跑代码很顺利所以心情也很好。
需要注意的一点是,案例中同时给出了java和go的代码,第一次把两个都跑了,事实上只需要选择一个就可。
建议还是用go。
在这里插入图片描述
第一部分的资产转移案例还有拓展内容,可以作为参考

https://blog.youkuaiyun.com/ling1998/article/details/127202209
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值