视频8
https://pkg.go.dev/github.com/hyperledger/fabric-chaincode-go/shim#section-sourcefiles
简单资产链码
我们的应用程序是一个基本的示例链码,用来在账本上创建资产(键-值对)。
选择一个位置存放代码
如果你没有写过 Go 的程序,你可能需要确认一下你是否安装了 Go 以及你的系统是否配置正确。我们假设你用的是支持模块的版本。
现在你需要为你的链码应用程序创建一个目录。
简单起见,我们使用如下命令:
mkdir sacc && cd sacc
现在,我们创建一个用于编写代码的源文件:
go mod init sacc
touch sacc.go
内务
首先,我们从内务开始。每一个链码都要实现 Chaincode 接口 中的 Init
和 Invoke
方法。所以,我们先使用 Go import 语句来导入链码必要的依赖。我们将导入链码 shim 包和 peer protobuf 包 。然后,我们加入一个 SimpleAsset
结构体来作为 Chaincode shim 方法的接收者。
package main
import (
"fmt"
"github.com/hyperledger/fabric-chaincode-go/shim"
"github.com/hyperledger/fabric-protos-go/peer"
)
// SimpleAsset implements a simple chaincode to manage an asset
type SimpleAsset struct {
}
初始化链码
然后,我们将实现 Init
方法。
// Init is called during chaincode instantiation to initialize any data.
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
}
注解
注意,链码升级的时候也要调用这个方法。当写一个用来升级已存在的链码的时候,请确保合理更改 Init
方法。特别地,当升级时没有“迁移”或者没东西需要初始化时,可以提供一个空的 Init
方法。
接下来,我们将使用 ChaincodeStubInterface.GetStringArgs 方法获取 Init
调用的参数,并且检查其合法性。在我们的用例中,我们希望得到一个键-值对。
// Init is called during chaincode instantiation to initialize any // data. Note that chaincode upgrade also calls this function to reset // or to migrate data, so be careful to avoid a scenario where you // inadvertently clobber your ledger's data! func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response { // Get the args from the transaction proposal args := stub.GetStringArgs() if len(args) != 2 { return shim.Error("Incorrect arguments. Expecting a key and a value") } }
接下来,我们已经确定了调用是合法的,我们将把初始状态存入账本中。我们将调用 ChaincodeStubInterface.PutState 并将键和值作为参数传递给它。假设一切正常,将返回一个 peer.Response 对象,表明初始化成功。
// Init is called during chaincode instantiation to initialize any
// data. Note that chaincode upgrade also calls this function to reset
// or to migrate data, so be careful to avoid a scenario where you
// inadvertently clobber your ledger's data!
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
// Get the args from the transaction proposal
args := stub.GetStringArgs()
if len(args) != 2 {
return shim.Error("Incorrect arguments. Expecting a key and a value")
}
// Set up any variables or assets here by calling stub.PutState()
// We store the key and the value on the ledger
err := stub.PutState(args[0], []byte(args[1]))
if err != nil {
return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))
}
return shim.Success(nil)
}
调用链码
首先,我们增加一个 Invoke
函数的签名。
// Invoke is called per transaction on the chaincode. Each transaction is
// either a 'get' or a 'set' on the asset created by Init function. The 'set'
// method may create a new asset by specifying a new key-value pair.
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
}
就像上边的 Init
函数一样,我们需要从 ChaincodeStubInterface
中解析参数。Invoke
函数的参数是将要调用的链码应用程序的函数名。在我们的用例中,我们的应用程序将有两个方法: set
和 get
,用来设置或者获取资产当前的状态。我们先调用 ChaincodeStubInterface.GetFunctionAndParameters 来为链码应用程序的方法解析方法名和参数。
// Invoke is called per transaction on the chaincode. Each transaction is
// either a 'get' or a 'set' on the asset created by Init function. The Set
// method may create a new asset by specifying a new key-value pair.
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
// Extract the function and args from the transaction proposal
fn, args := stub.GetFunctionAndParameters()
}
然后,我们将验证函数名是否为 set
或者 get
,并执行链码应用程序的方法,通过 shim.Success
或 shim.Error
返回一个适当的响应,这个响应将被序列化为 gRPC protobuf 消息。
// Invoke is called per transaction on the chaincode. Each transaction is
// either a 'get' or a 'set' on the asset created by Init function. The Set
// method may create a new asset by specifying a new key-value pair.
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
// Extract the function and args from the transaction proposal
fn, args := stub.GetFunctionAndParameters()
var result string
var err error
if fn == "set" {
result, err = set(stub, args)
} else {
result, err = get(stub, args)
}
if err != nil {
return shim.Error(err.Error())
}
// Return the result as success payload
return shim.Success([]byte(result))
}
实现链码应用程序
就像我们说的,我们的链码应用程序实现了两个功能,它们可以通过 Invoke
方法调用。我们现在来实现这些方法。注意我们之前提到的,要访问账本状态,我们需要使用链码 shim API 中的 ChaincodeStubInterface.PutState 和 ChaincodeStubInterface.GetState 方法。
// Set stores the asset (both key and value) on the ledger. If the key exists,
// it will override the value with the new one
func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
if len(args) != 2 {
return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value")
}
err := stub.PutState(args[0], []byte(args[1]))
if err != nil {
return "", fmt.Errorf("Failed to set asset: %s", args[0])
}
return args[1], nil
}
// Get returns the value of the specified asset key
func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
if len(args) != 1 {
return "", fmt.Errorf("Incorrect arguments. Expecting a key")
}
value, err := stub.GetState(args[0])
if err != nil {
return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)
}
if value == nil {
return "", fmt.Errorf("Asset not found: %s", args[0])
}
return string(value), nil
}
把它们组合在一起
最后,我们增加一个 main
方法,它将调用 shim.Start 方法。下边是我们链码程序的完整源码。
package main
import (
"fmt"
"github.com/hyperledger/fabric-chaincode-go/shim"
"github.com/hyperledger/fabric-protos-go/peer"
)
// SimpleAsset implements a simple chaincode to manage an asset
type SimpleAsset struct {
}
// Init is called during chaincode instantiation to initialize any
// data. Note that chaincode upgrade also calls this function to reset
// or to migrate data.
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
// Get the args from the transaction proposal
args := stub.GetStringArgs()
if len(args) != 2 {
return shim.Error("Incorrect arguments. Expecting a key and a value")
}
// Set up any variables or assets here by calling stub.PutState()
// We store the key and the value on the ledger
err := stub.PutState(args[0], []byte(args[1]))
if err != nil {
return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))
}
return shim.Success(nil)
}
// Invoke is called per transaction on the chaincode. Each transaction is
// either a 'get' or a 'set' on the asset created by Init function. The Set
// method may create a new asset by specifying a new key-value pair.
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
// Extract the function and args from the transaction proposal
fn, args := stub.GetFunctionAndParameters()
var result string
var err error
if fn == "set" {
result, err = set(stub, args)
} else { // assume 'get' even if fn is nil
result, err = get(stub, args)
}
if err != nil {
return shim.Error(err.Error())
}
// Return the result as success payload
return shim.Success([]byte(result))
}
// Set stores the asset (both key and value) on the ledger. If the key exists,
// it will override the value with the new one
func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
if len(args) != 2 {
return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value")
}
err := stub.PutState(args[0], []byte(args[1]))
if err != nil {
return "", fmt.Errorf("Failed to set asset: %s", args[0])
}
return args[1], nil
}
// Get returns the value of the specified asset key
func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
if len(args) != 1 {
return "", fmt.Errorf("Incorrect arguments. Expecting a key")
}
value, err := stub.GetState(args[0])
if err != nil {
return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)
}
if value == nil {
return "", fmt.Errorf("Asset not found: %s", args[0])
}
return string(value), nil
}
// main function starts up the chaincode in the container during instantiate
func main() {
if err := shim.Start(new(SimpleAsset)); err != nil {
fmt.Printf("Error starting SimpleAsset chaincode: %s", err)
}
}
链码访问控制
链码可以通过调用 GetCreator() 方法来使用客户端(提交者)证书进行访问控制决策。另外,Go shim 提供了扩展 API ,用于从提交者的证书中提取客户端标识用于访问控制决策,该证书可以是客户端身份本身,或者组织身份,或客户端身份属性。
例如,一个以键-值对表示的资产可以将客户端的身份作为值的一部分保存其中(比如以 JSON 属性标识资产主人),以后就只有被授权的客户端才可以更新键-值对。
详细信息请查阅 client identity (CID) library documentation
To add the client identity shim extension to your chaincode as a dependency, see 管理 Go 链码的扩展依赖.
将客户端身份 shim 扩展作为依赖添加到你的链码,请查阅 管理 Go 链码的扩展依赖 。
管理 Go 链码的扩展依赖
你的 Go 链码需要 Go 标准库之外的一些依赖包(比如链码 shim)。当链码安装到 peer 的时候,这些报的源码必须被包含在你的链码包中。如果你将你的链码构造为一个模块,最简单的方法就是在打包你的链码之前使用 go mod vendor
来 “vendor” 依赖。
go mod tidy
go mod vendor
这就把你链码的扩展依赖放进了本地的 vendor
目录。
当依赖都引入到你的链码目录后, peer chaincode package
和 peer chaincode install
操作将把这些依赖一起放入链码包中。
视频9
拉取项目
GOPATH`设置为`/root/go` 进入`GOPATH/src
cd $GOPATH/src && git clone https://github.com/sxguan/fabric-go-sdk.git
启动节点
cd ./fabric-go-sdk/fixtures/ && docker-compose up -d
启动项目
cd .. && go build && ./fabric-go-sdk
>> 开始创建通道......
>>>> 使用每个org的管理员身份更新锚节点配置...
>>>> 使用每个org的管理员身份更新锚节点配置完成
>> 创建通道成功
>> 加入通道......
>> 加入通道成功
>> 开始打包链码......
>> 打包链码成功
>> 开始安装链码......
>> 安装链码成功
>> 组织认可智能合约定义......
>>> chaincode approved by Org1 peers:
peer0.org1.example.com:7051
peer1.org1.example.com:9051
>> 组织认可智能合约定义完成
>> 检查智能合约是否就绪......
LifecycleCheckCCCommitReadiness cc = simplecc, = {map[Org1MSP:true]}
LifecycleCheckCCCommitReadiness cc = simplecc, = {map[Org1MSP:true]}
>> 智能合约已经就绪
>> 提交智能合约定义......
>> 智能合约定义提交完成
>> 调用智能合约初始化方法......
>> 完成智能合约初始化
>> 通过链码外部服务设置链码状态......
>> 设置链码状态完成
<--- 添加信息 --->: 18c0c86ce029d7de04461484976c5151992864b52ca28905d0ccf911443fdfcb
<--- 查询信息 --->: 123
algernon@algernon-Lenovo-Legion-Y7000:/opt/gopath/src$ go build && ./fabric-go-sdk
github.com/hyperledger/fabric-chaincode-go/shim/handler.go:11:2: cannot find package "github.com/golang/protobuf/proto" in any of:
/usr/local/go/src/github.com/golang/protobuf/proto (from $GOROOT)
/opt/gopath/src/github.com/golang/protobuf/proto (from $GOPATH)
github.com/hyperledger/fabric-protos-go/peer/snapshot.pb.go:10:2: cannot find package "github.com/golang/protobuf/ptypes/empty" in any of:
/usr/local/go/src/github.com/golang/protobuf/ptypes/empty (from $GOROOT)
/opt/gopath/src/github.com/golang/protobuf/ptypes/empty (from $GOPATH)
github.com/hyperledger/fabric-chaincode-go/shim/interfaces.go:7:2: cannot find package "github.com/golang/protobuf/ptypes/timestamp" in any of:
/usr/local/go/src/github.com/golang/protobuf/ptypes/timestamp (from $GOROOT)
/opt/gopath/src/github.com/golang/protobuf/ptypes/timestamp (from $GOPATH)
github.com/hyperledger/fabric-protos-go/peer/chaincode_shim.pb.go:11:2: cannot find package "google.golang.org/grpc" in any of:
/usr/local/go/src/google.golang.org/grpc (from $GOROOT)
/opt/gopath/src/google.golang.org/grpc (from $GOPATH)
github.com/hyperledger/fabric-protos-go/peer/chaincode_shim.pb.go:12:2: cannot find package "google.golang.org/grpc/codes" in any of:
/usr/local/go/src/google.golang.org/grpc/codes (from $GOROOT)
/opt/gopath/src/google.golang.org/grpc/codes (from $GOPATH)
github.com/hyperledger/fabric-chaincode-go/shim/internal/client.go:13:2: cannot find package "google.golang.org/grpc/credentials" in any of:
/usr/local/go/src/google.golang.org/grpc/credentials (from $GOROOT)
/opt/gopath/src/google.golang.org/grpc/credentials (from $GOPATH)
github.com/hyperledger/fabric-chaincode-go/shim/internal/client.go:14:2: cannot find package "google.golang.org/grpc/keepalive" in any of:
/usr/local/go/src/google.golang.org/grpc/keepalive (from $GOROOT)
/opt/gopath/src/google.golang.org/grpc/keepalive (from $GOPATH)
github.com/hyperledger/fabric-protos-go/peer/chaincode_shim.pb.go:13:2: cannot find package "google.golang.org/grpc/status" in any of:
/usr/local/go/src/google.golang.org/grpc/status (from $GOROOT)
/opt/gopath/src/google.golang.org/grpc/status (from $GOPATH)
go build && ./fabric-go-sdk
>> 开始创建通道......
>> Create channel and join error: Create channel error: error should be nil for SaveChannel of orgchannel: create channel failed: create channel failed: SendEnvelope failed: calling orderer 'orderer.example.com:7050' failed: Orderer Client Status Code: (2) CONNECTION_FAILED. Description: dialing connection on target [orderer.example.com:7050]: connection is in TRANSIENT_FAILURE
go build && ./fabric-go-sdk
>> 开始创建通道......
>> Create channel and join error: Create channel error: error should be nil for SaveChannel of orgchannel: create channel failed: create channel failed: SendEnvelope failed: calling orderer 'orderer.example.com:7050' failed: Orderer Server Status Code: (400) BAD_REQUEST. Description: error applying config update to existing channel 'mychannel': error authorizing update: error validating ReadSet: proposed update requires that key [Group] /Channel/Application be at version 0, but it is currently at version 1
文章来源:https://www.toymoban.com/news/detail-661083.html
go build && ./fabric-go-sdk
>> 开始创建通道......
>>>> 使用每个org的管理员身份更新锚节点配置...
>>>> 使用每个org的管理员身份更新锚节点配置完成
>> 创建通道成功
>> 加入通道......
>> 加入通道成功
>> 开始打包链码......
>> 打包链码成功
>> 开始安装链码......
[fabsdk/fab] 2022/10/26 15:19:14 UTC - peer.(*peerEndorser).sendProposal -> ERRO process proposal failed [rpc error: code = DeadlineExceeded desc = context deadline exceeded]
[fabsdk/fab] 2022/10/26 15:19:14 UTC - peer.(*peerEndorser).sendProposal -> ERRO process proposal failed [rpc error: code = DeadlineExceeded desc = context deadline exceeded]
>> create chaincode lifecycle error: %v installCC error: LifecycleInstallCC error: Multiple errors occurred: - Transaction processing for endorser [peer0.org1.example.com:7051]: gRPC Transport Status Code: (4) DeadlineExceeded. Description: context deadline exceeded - Transaction processing for endorser [peer1.org1.example.com:9051]: gRPC Transport Status Code: (4) DeadlineExceeded. Description: context deadline exceeded
go build && ./fabric-go-sdk
>> 开始创建通道......
>>>> 使用每个org的管理员身份更新锚节点配置...
>>>> 使用每个org的管理员身份更新锚节点配置完成
>> 创建通道成功
>> 加入通道......
>> 加入通道成功
>> 开始打包链码......
>> 打包链码成功
>> 开始安装链码......
>> 安装链码成功
>> 组织认可智能合约定义......
>>> chaincode approved by Org1 peers:
peer0.org1.example.com:7051
peer1.org1.example.com:9051
>> 组织认可智能合约定义完成
>> 检查智能合约是否就绪......
LifecycleCheckCCCommitReadiness cc = simplecc, = {map[Org1MSP:true]}
LifecycleCheckCCCommitReadiness cc = simplecc, = {map[Org1MSP:true]}
>> 智能合约已经就绪
>> 提交智能合约定义......
>> 智能合约定义提交完成
>> 调用智能合约初始化方法......
>> 完成智能合约初始化
>> 通过链码外部服务设置链码状态......
>> 设置链码状态完成
<--- 添加信息 --->: 18c0c86ce029d7de04461484976c5151992864b52ca28905d0ccf911443fdfcb
<--- 查询信息 --->: 123
完整内容
https://sxguan0529.gitbook.io/hyperledger-fabric/fabric-sdk-go#san-pei-zhi-wen-jian-config.yaml文章来源地址https://www.toymoban.com/news/detail-661083.html
到了这里,关于【区块链技术与应用】(四)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!