Hyperledger fabric智能合约实战--存证溯源案例1.0

存证溯源案例1.0整体规划

为了持续的进行信息的更新,以及对账本进行管理(写入交易,进行查询等),区块链网络引入了智能合约来实现对账本的访问和控制;智能合约在 Fabric 中可以简单的理解为链码,是区块链应用的业务逻辑。

本文分享如何使用 Go 语言和Fabric 2.0链码开发fabric智能合约实战案例-存证溯源案例,借存证溯源案例来熟练fabric的智能合约开发基本用法,下图为本文大致内容。

在这里插入图片描述

一、fabric链码版本区别

本节简单介绍下fabric链码版本区别,详情区别请查看之前的技术文章:
Hyperledger fabric智能合约编写(一)

####1、导入包的不同
1.x导入的包为:


"[github.com/hyperledger/fabric/core/chaincode/shim](http://github.com/hyperledger/fabric/core/chaincode/shim)"

  pb "[github.com/hyperledger/fabric/protos/peer](http://github.com/hyperledger/fabric/protos/peer)"

2.0导入的包为:


"[github.com/hyperledger/fabric-contract-api-go/contractapi](http://github.com/hyperledger/fabric-contract-api-go/contractapi)"

####2、方法结构不同
Fabric2.0链码中不需要invoke和init方法
####3、方法中调用形式参数类型、返回值不同
1.x方法为:

createCar1(stub shim.ChaincodeStubInterface, args []string) pb.Response { }

2.x方法为:

Create(ctx contractapi.TransactionContextInterface,key string,value string)error { }

二、初始化

初始化代码示例:

//设置存证溯源记录的结构
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
}

三、账本操作

1、账本ledger与state数据库

fabric中的ledger分为两部分内容,一部分是基于文件的存储,基于文件的存储满足区块链不可篡改的特性,此种方式存储基本是采用Merkle Tree,整个存储的方式是只能追加,不能删除和修改。另一部分则是使用数据库进行存储此种方式在fabric中叫做world state,如leveldb、couchdb等K-V数据库(也叫状态数据库,state DB),使用此类数据库的优势是数据库只存储当前的最新值,便于业务的拓展,这样可以很快的查找到当前的值,而无需通过遍历的方式来查找。

无论是world state 还是文件存储都是分布式的存储,在多个节点里都存在副本的。通过共识保证数据在各个节点上的一致性。couchdb和leveldb都可以作为state的数据库,但是couchdb在处理json和富查询方面有着独特的的优势。fabric 此处可以支持插件方式的数据库,可以是关系型,图形数据库等,这样便于fabric扩展。

链码中,我们通常基于业务流程需要来操作state数据库作为账本操作,以下为账本操作基本内容。

2、创建Asset

创建Asset代码示例:

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)
}
3、查询Asset

查询Asset代码示例:

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
}
4、修改Asset

修改Asset代码示例:

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)
}
5、删除Asset

删除Asset代码示例:

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

四、Asset溯源

Asset溯源代码示例:

//溯源查询结果结构体
type HistoryQueryResult struct {
	Record    *Asset    `json:"record"`
	TxId      string    `json:"txId"`
	Timestamp time.Time `json:"timestamp"`
	IsDelete  bool      `json:"isDelete"`
}
//Asset溯源结果查询
func (t *SimpleChaincode) GetAssetHistory(ctx contractapi.TransactionContextInterface, assetID string) ([]HistoryQueryResult, error) {
	log.Printf("GetAssetHistory: ID %v", assetID)

	resultsIterator, err := ctx.GetStub().GetHistoryForKey(assetID)
	if err != nil {
		return nil, err
	}
	defer resultsIterator.Close()

	var records []HistoryQueryResult
	for resultsIterator.HasNext() {
		response, err := resultsIterator.Next()
		if err != nil {
			return nil, err
		}

		var asset Asset
		if len(response.Value) > 0 {
			err = json.Unmarshal(response.Value, &asset)
			if err != nil {
				return nil, err
			}
		} else {
			asset = Asset{
				ID: assetID,
			}
		}

		timestamp, err := ptypes.Timestamp(response.Timestamp)
		if err != nil {
			return nil, err
		}

		record := HistoryQueryResult{
			TxId:      response.TxId,
			Timestamp: timestamp,
			Record:    &asset,
			IsDelete:  response.IsDelete,
		}
		records = append(records, record)
	}

	return records, nil
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值