Chaincode開発環境とこんにちは
Chaincodeの使用GO LANG開発
# 安装Golang的SDK
go get github.com/hyperledger/fabric-sdk-go
# 安装shim包
go get -u github.com/hyperledger/fabric/core/chaincode/shim
チェーンコードがスタートシムパック関数を呼び出すことによって開始し、開始関数が呼び出されたときのタイプChaincodeの引数を渡す必要する必要があり、このパラメータはChaincodeインターフェイスタイプで、インターフェースは、2つの重要な機能を持ってい--initそして起動。
type Chaincode interface{
Init(stub ChaincodeStubInterface) peer.Response
Invoke(stub ChaincodeStubInterface) peer.Response
}
- INIT:チェーンを初期化データの終了、インスタンス化またはアップグレードコードと呼ばれています。
- 呼び出しは次の場合、更新またはクエリデータ状態元帳提案業務と呼ばれるので、この機能は実装を作成するためにビジネスロジックを達成するために、通話や問い合わせに応答されます。
実際の開発では、開発者は、以下の構造を定義し、構造定義された2つのメンバ・メソッドから機能Chaincode二つのインターフェース、および指定された機能を無効にすることができ
必要な構造
package main
// 引入必要的包
import (
"fmt"
// shim包提供了链码与账本交互的中间层
// 链码通过shim.ChaincodeStub提供的相应函数来读取和修改账本的状态
"github.com/hyperledger/fabric/core/chiancode/shim"
// 链码被调用执行之后通过peer包中的Response来封装执行结果的响应信息
"github.com/hyperledger/fabric/protos/peer"
)
// 声明一个结构体
type SimpleChaincode struct {
}
// 为结构体添加Init函数
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response {
// 在该方法中实现链码初始化或升级时的处理逻辑
// 编写时可灵活使用stub中的API
}
// 为结构体添加Init函数
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
// 该方法中实现链码运行中被调用或查询时的处理逻辑
// 编写时可灵活使用stub中的API
}
// 主函数,需要调用shim.Start()方法
func main() {
err := shim.Start(new(SimpleChaincode))
if err != nil {
fmt.Print("Error starting Simple chaincode: %s", err)
}
}
APIシム用パック
パラメータ解析API
- GetArgs()[][]byte: 返回调用链码时在交易提案中指定提供的被调用函数及参数列表
- GetArgsSlice() ([]byte, error): 返回调用链码时在交易提案中指定提供的参数列表
- GetFunctionAndParameters() (function string, Params[]string): 返回调用链码时在交易提案中指定提供的被调用函数名称及其参数列表
- GetStringArgs()[]string: 返回调用链码时指定提供的参数列表
本データ状態操作API
- GetState(key string) ([]byte, error): 根据指定的key查询相应的数据状态
- PutState(key string, value[]byte) error: 根据指定的key,将对应的value保存在分类账本中
- DelState(key string) error: 根据指定的key将对应的数据状态删除
- GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error): 根据指定的开始key及结束key,查询范围内的所有数据状态。注意结束key对应的数据状态不包含在返回的结果集中。
- GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error): 根据指定的key查询所有的历史纪录信息。
- CreateCompositeKey(objectType string, attributes[]string) (string, error): 创建一个复合键。
- SplitCompositeKey(compositeKey string) (string, []string, error): 对指定的复合键进行分割。
- GetQueryResult(query string) (StateQueryIteratorInterface, error): 对(支持富查询功能的)状态数据库进行富查询
取引情報API
- GetTxID() string: 返回交易提案中指定的交易ID
- GetChannelID() string: 返回交易提案中指定的通道ID
- GetTxTimestamp() (*timestamp.Timestamp, error): 返回交易创建的时间戳,这个时间戳时Peer接收到交易的具体时间
- GetBinding() ([]byte, error): 返回交易的绑定信息,如一些临时信息,以避免重复性攻击
- GetSignedProposal() (*pb.SignedProposal, error): 返回与交易提案相关的签名身份信息
- GetCreator() ([]byte, error): 返回该交易提交者的身份信息
- GetTransient() (map[string][]byte, error): 返回交易中不会被写至账本中的一些临时信息
イベント処理API
- SetEvent(name string, payload[]byte) error: 设置事件,包括事件名称及内容
PrivateDataのAPI操作
- GetPrivateData(collection string , key string) ([]byte, error): 根据指定的key,从指定的私有数据集中查询对应的私有数据
- PutPrivateData(collection string, key string, value[]byte) error: 将指定的key与value保存到私有数据集中
- DelPrivateData(collection string, key string) error: 根据指定的key从私有数据集中删除相应的数据
- GetPrivateDataByRange(collection string, startKey, endKey string) (State-QueryIteratorInterface, error): 根据指定的开始key与结束key查询范围(不包含结束key)内的私有数据
- GetPrivateDataByPartialCompositeKey(collection string, objectType string, keys[]string) (StateQueryIteratorInterface, error): 根据给定的部分组合键的集合,查询给定的私有状态
- GetPrivateDataQueryResult(collection string, query string) (StateQueryIteratorInterface, error): 根据指定的查询字符串执行富查询
チェーンコード開発こんにちは
ファブリック・サンプル/ chaincodeディレクトリに最初のディレクトリハローを作成します。
チェーンコードファイルを作成します。vim hello.go
// hello.go
package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer"
)
type HelloChaincode struct{}
// 实例化/升级链码时被自动调用
// -c '{"Args": ["Hello", "World"]}'
func (t *HelloChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response {
fmt.Println("开始实例化链码......")
// 获取参数
// args := stub.GetStringArgs()
_, args := stub.GetFunctionAndParameters()
// 判断参数长度是否为2个
if len(args) != 2 {
return shim.Error("指定了错误的参数个数")
}
fmt.Println("保存数据......")
// 通过调用PutState函数将数据保存在账本中
err := stub.PutState(args[0], []byte(args[1]))
if err != nil {
return shim.Error("保存数据时发生错误")
}
fmt.Println("实例化链码成功")
return shim.Success(nil)
}
// 对账本数据进行操作时被自动调用(query, invoke)
func (t *HelloChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
// 获取调用链码时传递的参数内容(包括要调用的函数名及参数)
fun, args := stub.GetFunctionAndParameters()
// 客户意图
if fun == "query" {
return query(stub, args)
}
return shim.Error("非法操作, 指定功能不能实现")
}
func query(stub shim.ChaincodeStubInterface, args []string) peer.Response {
// 检查传递的参数是否为1
if len(args) != 1 {
return shim.Error("指定的参数错误, 必须且只能指定相应的Key")
}
// 根据指定的Key调用GetState方法查询数据
result, err := stub.GetState(args[0])
if err != nil {
return shim.Error("根据指定的 " + args[0] + " 查询数据时发生错误")
}
if result == nil {
return shim.Error("根据指定的 " + args[0] + " 没有查询到相应的数据")
}
// 返回查询结果
return shim.Success(result)
}
func main() {
err := shim.Start(new(HelloChaincode))
if err != nil {
fmt.Printf("chaincode start failed: %v", err)
}
}
チェーンコードのテスト
まず、入力したgithub.com/hyperledger/fabric-samples/chaincode-docker-devmode
ディレクトリを、Devの開発テストモードは、チェーンコードを開始します
ドッカーは、最初のフラッシュのコマンドで、環境についての物品の使用を空にする
設定docker-compose-simple.yaml
ファイルは、ミラーのタグを使用して、独自にタグのYAMLファイルは、画像で使用されるすべては、それを変更、またはドッキングウィンドウ-ハブから画像を引っ張って持ってきました
services:
orderer:
container_name: orderer
image: hyperledger/fabric-orderer:1.4 # 就是这里
environment:
- FABRIC_LOGGING_SPEC=debug
- ORDERER_GENERAL_LISTENADDRESS=orderer
- ORDERER_GENERAL_GENESISMETHOD=file
- ORDERER_GENERAL_GENESISFILE=orderer.block
- ORDERER_GENERAL_LOCALMSPID=DEFAULT
- ORDERER_GENERAL_LOCALMSPDIR=/etc/hyperledger/msp
- GRPC_TRACE=all=true,
- GRPC_VERBOSITY=debug
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
command: orderer
volumes:
- ./msp:/etc/hyperledger/msp
- ./orderer.block:/etc/hyperledger/fabric/orderer.block
ports:
- 7050:7050
[スタート]ドッキングウィンドウコンテナ
docker-compose -f docker-compose-simple.yaml up -d
docker ps
環境の状態を見てください
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
073c62bb15d5 hyperledger/fabric-tools:1.4 "/bin/bash -c ./scri…" 6 seconds ago Up 3 seconds cli
6e78e11d6b1f hyperledger/fabric-ccenv:1.4 "/bin/sh -c 'sleep 6…" 6 seconds ago Up 2 seconds chaincode
eeb2dd0e8509 hyperledger/fabric-peer:1.4 "peer node start --p…" 7 seconds ago Up 5 seconds 0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp peer
c9cdcf50b042 hyperledger/fabric-orderer:1.4 "orderer" 8 seconds ago Up 6 seconds 0.0.0.0:7050->7050/tcp orderer
この正常なスタートコンテナ
- チェーンコード環境のChaincodeコンテナ
- チェーンコードと対話するためのCLI容器
そして、コンテナchaincodeへ
docker exec -it chaincode bash
# 进入chaincode容器后, 进入存有chaincode的目录编译链码
cd hello
go build
チェーンコードを起動します。
CORE_PEER_ADDRESS=peer:7052
CORE_CHAINCODE_ID_NAME=hellocc:0 ./hello
- CORE_PEER_ADDRESS:ピアを指定するために使用
- CORE_CHAINCODE_ID_NAME:チェーンコードへの登録のためのピア
- hellocc:指定チェーンコード名
- 0:指定した初期バージョンのチェーンコード
- ./hello:指定チェーンコードファイル
CORE_PEER_ADDRESS =ピア:7052CORE_PEER_ADDRESS =ピア:70527052何を意味するかのポート、およびなぜ7051?
7052は、指定されたチェーンコードを聞くためにプライベートアドレスとポート番号であり、7051は、ネットワークポートピア・ノードリッスンです
通常のスタートは、次のことを示しています。
root@6e78e11d6b1f:/opt/gopath/src/chaincode/hello# CORE_CHAINCODE_ID_NAME=hellocc:0 ./hello
2020-02-25 16:51:41.309 UTC [shim] setupChaincodeLogging -> INFO 001 Chaincode log level not provided; defaulting to: INFO
2020-02-25 16:51:41.310 UTC [shim] setupChaincodeLogging -> INFO 002 Chaincode (build level: ) starting up ...
新しいターミナルを開き、CLIコンテナを入力します。
docker exec -it cli bash
# 安装链码时指定的链码名称与版本号必须与在之前chaincode容器中注册的链码名称及版本号相同
peer chaincode install -p chaincodedev/chiancode/hello -n hellocc -v 0
チェーンコードの例:
peer chaincode instantiate -n hellocc -v 0 -c '{"Args":["init","Hello","World"]}' -C myc
コールチェーンコード:
peer chaincode query -n hellocc -c '{"Args":["query","Hello"]}' -C myc
最後に返されたWorld
呼び出しが成功し、