链码就是 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/JS | Solidity/Vyper/Rust |
| 初始化 | Init (显式) | constructor (显式) |
| 确定性保障 | 开发者责任 | EVM 架构保障 |
> ← 15.2 搭建网络 | 前往 → 15.4 链码生命周期与升级 |*
评论
0评论加载中…