fabric1.4如何开发实现system chaincode(
2020-08-15 本文已影响0人
CodingCode
这里介绍如果使用plugin的方式实现system chaincode。
在fabric1.4版本里缺省情况下不支持plugin方式的system chaincode;所以即使部署了插件的so文件,peer也不会去加载。
所以:
- 打开peer的pluginsenabled开关,重写编译peer
$ GO_TAGS="pluginsenabled" make peer
或者在fabric/Makefile里面直接修改
--- a/src/github.com/hyperledger/fabric/Makefile
+++ b/src/github.com/hyperledger/fabric/Makefile
@@ -78,7 +78,7 @@ METADATA_VAR += BaseDockerNamespace=$(BASE_DOCKER_NS)
GO_LDFLAGS = $(patsubst %,-X $(PKGNAME)/common/metadata.%,$(METADATA_VAR))
-GO_TAGS ?=
+GO_TAGS ?= pluginsenabled
然后重新编译peer,部署peer到container里面
- 生成system chaincode代码
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"fmt"
"github.com/hyperledger/fabric/common/flogging"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
// New returns an instance of MYSCC.
// Typically this is called once per peer.
//func New() *MySccImp {
func New() shim.Chaincode {
return &MySccImp{
}
}
// MySccImp implements the ledger query functions, including:
// - Add add a record
// - Query query a record
type MySccImp struct {
}
var myscclogger = flogging.MustGetLogger("myscc")
// These are function names from Invoke first parameter
const (
PUT string = "Put"
GET string = "Get"
)
// Init is called once per chain when the chain is created.
// This allows the chaincode to initialize any variables on the ledger prior
// to any transaction execution on the chain.
func (e *MySccImp) Init(stub shim.ChaincodeStubInterface) pb.Response {
myscclogger.Info("Init MYSCC")
return shim.Success(nil)
}
// Invoke is called with args[0] contains the query function name, args[1]
// contains the chain ID, which is temporary for now until it is part of stub.
// Each function requires additional parameters as described below:
// # Add: Return a BlockchainInfo object marshalled in bytes
// # Query: Return the block specified by block number in args[2]
func (e *MySccImp) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
args := stub.GetArgs()
if len(args) < 2 {
return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args)))
}
fname := string(args[0])
key := string(args[1])
myscclogger.Debugf("Invoke function: %s on chain: %s", fname, key)
switch fname {
case PUT:
if len(args) < 3 {
return shim.Error(fmt.Sprintf("missing 3rd argument for %s", fname))
}
value := args[2]
return Put(stub, key, value)
case GET:
return Get(stub, key)
default:
return shim.Error(fmt.Sprintf("Requested function %s not found.", fname))
}
}
func Put(stub shim.ChaincodeStubInterface, key string, value []byte) pb.Response {
stub.PutState(key, value)
return shim.Success(nil)
}
func Get(stub shim.ChaincodeStubInterface, key string) pb.Response {
value, err := stub.GetState(key)
if err != nil {
return shim.Error(fmt.Sprintf("unable get key %s, error: %v", key, err))
}
return shim.Success(value)
}
func main() {}
和前面介绍的直接链接在peer文件内的system chaincode比较有几点注意。
- package名字必须是main啦
- 必须包含一个空main()函数啦,否则编译不过。
- 即使定义成非空函数,这个main也不会被执行。
- New函数必须定义成
func New() shim.Chaincode
,否则会报错peer: panic: Function New does not match expected definition func() shim.Chaincode
- 不能带参数,(对照内置的用法,这里不能传ACL参数对象,可能对ACL的使用有限制???)
- 返回类型必须是shim.Chaincode,不能是扩展了的struct,例如
func New() *MySccImp
,虽然MySccImp实现了shim.Chaincode的接口,也不行;
- 编译system chaincode
$ go build -buildmode=plugin -o myscc.so myscc.go
注意:
- plugin的编译必须和peer的编译使用相同的编译环境,包括go语言,依赖库版本等,否则运行的时候出乱七八糟的问题:
fabric plugin was built with a different version of package <name>
。 - 编译出来的.so文件缺省没有可执行权限,这也不需要,peer加载的时候不管这个。
- 部署system chaincode
把myscc.so拷贝的peer container里面,同时修改core.yaml两个地方:
# system chaincodes whitelist. To add system chaincode "myscc" to the
# whitelist, add "myscc: enable" to the list below, and register in
# chaincode/importsysccs.go
system:
cscc: enable
lscc: enable
escc: enable
vscc: enable
qscc: enable
+ myscc: enable
# System chaincode plugins: in addition to being imported and compiled
# into fabric through core/chaincode/importsysccs.go, system chaincodes
# can also be loaded as shared objects compiled as Go plugins.
# See examples/plugins/scc for an example.
# Like regular system chaincodes, plugins must also be white listed in the
# chaincode.system section above.
systemPlugins:
# example configuration:
+ - enabled: true
+ name: myscc
+ path: /path/to/myscc.so
+ invokableExternal: true
+ invokableCC2CC: true
重启peer就可以使用了。