教程区块链区块链技术ch1515.3 链码(Chaincode)开发:以资产溯源为例

本页目录

链码就是 Fabric 的智能合约。与公链不同,链码运行在 Docker 容器中,有明确的生命周期管理,且支持多种语言(Go、Java、JavaScript)。Go 是生产首选。


15.3.1 链码接口与状态管理

链码必须实现两个接口:

  • Init:通道实例化时调用,初始化账本
  • Invoke:每个交易调用的入口
go
// Chaincode 接口(简化,展示核心思路)
type Chaincode interface {
    Init(stub ChaincodeStubInterface) PeerResponse
    Invoke(stub ChaincodeStubInterface) PeerResponse
}

状态 API

graph LR
    Get[GetState] --> |读取| World[世界状态数据库]
    Put[PutState] --> |写入| World
    Del[DelState] --> |删除| World
    GetHistory --> |查询| World
    
    style World fill:#e8f5e9

15.3.2 资产溯源链码(Go 骨架)

go
// asset_transfer.go
package main

import (
	"encoding/json"
	"fmt"
	"github.com/hyperledger/fabric-contract-api-go/contractapi"
)

// 资产数据结构
type Asset struct {
	DocType     string `json:"docType"`     // 区分记录类型
	ID          string `json:"id"`          // VIN 码
	Color       string `json:"color"`
	Size        int    `json:"size"`
	Owner       string `json:"owner"`
	AppraisedValue int `json:"appraisedValue"` // 认证价值
	Manufacturer  string `json:"manufacturer"` // 生产商
	ProductionDate string `json:"productionDate"`

}

// 智能合约类
type SmartContract struct {
	contractapi.Contract
}

// 初始化账本(5 辆汽车示例)
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
	assets := []Asset{
		{ID: "asset1", Color: "blue", Size: 5, Owner: "Tom", AppraisedValue: 3000, Manufacturer: "Toyota", ProductionDate: "2022-01-15"},
		{ID: "asset2", Color: "red", Size: 5, Owner: "Brad", AppraisedValue: 4000, Manufacturer: "Honda", ProductionDate: "2021-11-20"},
		// ... 更多
	}
	
	for _, a := range assets {
		assetJSON, _ := json.Marshal(a)
		// 写入世界状态:键 = 资产ID,值 = JSON 字节
		err := ctx.GetStub().PutState(a.ID, assetJSON)
		if err != nil {
			return fmt.Errorf("添加资产 %s 失败: %v", a.ID, err)
		}
	}
	return nil
}

// 创建资产
func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, 
	id, color, owner string, size, value int) error {
	
	// 检查是否已存在
	exists, _ := ctx.GetStub().GetState(id)
	if exists != nil {
		return fmt.Errorf("资产 %s 已存在", id)
	}
	
	asset := Asset{
		DocType:   "asset",
		ID:        id,
		Color:     color,
		Size:      size,
		Owner:     owner,
		AppraisedValue: value,
		Manufacturer: "Factory-1",
		ProductionDate: "2024-01-01",
	}
	
	assetJSON, _ := json.Marshal(asset)
	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 || assetJSON == nil {
		return nil, fmt.Errorf("资产 %s 不存在", id)
	}
	var asset Asset
	err = json.Unmarshal(assetJSON, &asset)
	return &asset, err
}

// 转移所有权
func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, 
	id string, newOwner string) error {
	
	asset, err := s.ReadAsset(ctx, id)
	if err != nil {
		return err
	}
	asset.Owner = newOwner
	assetJSON, _ := json.Marshal(asset)
	return ctx.GetStub().PutState(id, assetJSON)
}

// 查询某人的所有资产
func (s *SmartContract) QueryAssetsByOwner(ctx contractapi.TransactionContextInterface, 
	owner string) ([]*Asset, error) {
	
	// 在链码中简单遍历(仅小规模数据)
	// 大规模需配合 CouchDB 富查询
	results := []*Asset{}
	
	// 使用 GetStateByRange 或 Rich Query
	// 注意:遍历全状态范围在生产中性能差
	// 生产上使用 CouchDB 的 JSON 查询
	
	return results, nil
}

func main() {
	chaincode, _ := contractapi.NewChaincode(&SmartContract{})
	chaincode.Start()
}

15.3.3 背书策略

必须理解:部署时指定

bash
# 安装到两个组织的 peer
peer chaincode install -n assettransfer -v 1.0 -p ./

# 批准(每个组织执行一次)
peer lifecycle chaincode approveformyorg \
  -o orderer.example.com:7050 \
  --channelID mychannel \
  --name assettransfer \
  --version 1.0 \
  --package-id $PACKAGE_ID \
  --sequence 1 \
  --signature-policy "OR('Org1MSP.peer', 'Org2MSP.peer')"
  # 即:组织1或组织2的任一peer背书即可

# 提交(任意一个组织提交,当足够多组织已批准)
peer lifecycle chaincode commit ...

策略语法

策略含义示例
AND(a, b)a 和 b 都必须双组织必须
OR(a, b)a 或 b 任一任一组织
NOutOf(n, [a,b,c...])N 个中的 n 个2/3 多签
MSP.peer该 MSP 的 peer'Org1MSP.peer'

15.3.4 与公链合约的对照

维度Fabric 链码公链合约 (Solidity)
确定性编写者保证编程模型内建(gas限制)
共识执行-排序-验证执行+排序同时 + 验证
升级支持(版本管理)需代理模式
隐私通道隔离 + 私有集合全公开
语言Go/Java/JSSolidity/Vyper/Rust
初始化Init (显式)constructor (显式)
确定性保障开发者责任EVM 架构保障

> ← 15.2 搭建网络 | 前往 → 15.4 链码生命周期与升级 |*

评论

0

评论加载中…

发表评论

0/2000