fabric搭建基础的测试网络
Fabric 基础读写性能实验:
先清空一下环境
cd fabric-samples/test-network./network.sh down # 清理旧环境
./network.sh up createChannel -ca # 启动网络并创建通道
预期输出: 成功启动两个组织(Org1, Org2)、一个排序服务和创建 mychannel 通道。
接着我们自己编写一个链码
我们将创建一个简单的 Go 链码,实现 Put (写入) 和 Get (读取) 方法。
创建链码项目目录:
在 fabric-samples/chaincode 目录下创建。
mkdir -p basic-kv
cd basic-kv
go mod init basic-kv
编写链码 (basic-kv.go):
创建 basic-kv.go 文件,并将以下内容粘贴进去。
package mainimport ("encoding/json""fmt""github.com/hyperledger/fabric-contract-api-go/contractapi"
)// SmartContract provides functions for managing assets
type SmartContract struct {contractapi.Contract
}// Asset describes basic details of what we want to store
type Asset struct {ID string `json:"ID"`Value string `json:"Value"` // Generic value field
}// InitLedger adds a base set of assets to the ledger
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {// No initial data for performance test, but required for instantiationfmt.Printf("Chaincode initialized.\n")return nil
}// PutAsset stores a new asset
func (s *SmartContract) PutAsset(ctx contractapi.TransactionContextInterface, assetID string, value string) error {exists, err := s.AssetExists(ctx, assetID)if err != nil {return fmt.Errorf("failed to read from world state: %v", err)}if exists {return fmt.Errorf("the asset %s already exists", assetID)}asset := Asset{ID: assetID,Value: value,}assetJSON, err := json.Marshal(asset)if err != nil {return err}return ctx.GetStub().PutState(assetID, assetJSON)
}// GetAsset retrieves an asset by ID
func (s *SmartContract) GetAsset(ctx contractapi.TransactionContextInterface, assetID string) (*Asset, error) {assetJSON, err := ctx.GetStub().GetState(assetID)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", assetID)}var asset Asseterr = json.Unmarshal(assetJSON, &asset)if err != nil {return nil, err}return &asset, nil
}// AssetExists returns true if asset with given ID exists in world state
func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, assetID string) (bool, error) {assetJSON, err := ctx.GetStub().GetState(assetID)if err != nil {return false, fmt.Errorf("failed to read from world state: %v", err)}return assetJSON != nil, nil
}func main() {chaincode, err := contractapi.NewChaincode(&SmartContract{})if err != nil {fmt.Printf("Error creating basic-kv chaincode: %v", err)return}if err := chaincode.Start(); err != nil {fmt.Printf("Error starting basic-kv chaincode: %v", err)}
}
然后我们先运行
go mod tidy
先把一些需要的依赖下载下来
返回test-network 目录,接着部署我们的链码
./network.sh deployCC -ccn basic-kv -ccp ../chaincode/basic-kv -ccv 1.0 -ccl go -c mychannel
预期输出: 链码成功安装、定义和提交。最后会看到 Chaincode ‘basic-kv’ now defined on channel ‘mychannel’ on Org1 and Org2.
客户端工具准备
我们将使用 Fabric CLI 来手动测试,并建议使用 Go SDK 或 Node.js SDK 编写脚本进行批量测试。这里为了简化,先用 CLI 演示。
设置
# Set the path to the Fabric test-network directory if not already there
# export PATH=$PATH:/path/to/fabric-samples/bin # Ensure fabric binaries are in PATH
# export FABRIC_CFG_PATH=/path/to/fabric-samples/config # Point to Fabric configexport 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 # Or the correct address for peer0.org1echo "Environment variables set for Org1 Peer0 Admin."
可以去organizations/peerOrganizations/org1.example.com/下创建一个env.sh,内容就是上面的代码
. ./organizations/peerOrganizations/org1.example.com/env.sh
这个命令可以运行上面的脚本
这个命令是用来设置当前 shell 会话的环境变量,以便你可以作为 Org1 的管理员用户来操作 peer 节点
可以通过下面的命令来查看是否配置成功(尝试查询链码版本)
peer lifecycle chaincode queryinstalled --output json
一般输出下面的内容
{"installed_chaincodes": [ // 这是一个数组,表示当前Peer节点上所有已安装的链码{"package_id": "basic-kv_1.0:ad7fa25e655b71713da784a048b697cba6c4e773db7e9f34e9fdbfd27334c467",// "package_id" 是链码包的唯一标识符。// 它由链码的 "label"(这里是 "basic-kv_1.0")和一个哈希值(表示链码包的内容哈希)组成。// 这个ID在安装链码时生成,并且在后续定义/提交链码到通道时会用到。"label": "basic-kv_1.0",// "label" 是你在打包和安装链码时给它指定的用户可读的名称和版本。// 它有助于识别链码的不同版本。"references": { // "references" 表示这个链码包被哪些通道上的哪些链码定义所引用。"mychannel": { // 这个链码包在 "mychannel" 通道上被引用。"chaincodes": [ // "chaincodes" 数组列出了在该通道上使用此链码包的链码定义。{"name": "basic-kv",// "name" 是链码在特定通道上被“定义”和“提交”时的名称。// 在你的部署命令中,这是 `-ccn basic-kv` 指定的。// 这是你在调用链码时实际使用的名称。"version": "1.0"// "version" 是链码在通道上定义的版本。// 在你的部署命令中,这是 `-ccv 1.0` 指定的。}]}}}]
}
然后环境配置完了,就可以运行脚本进行测试,我们脚本的本质就是调用命令进行查询或者提交提案 官方链接