这篇文章介绍如何在fabric1.4里面实现一个system chaincode的例子。
(实现一个system chaincode的例子可以用插件(在fabric1.4版本中缺省情况下已经被禁用了),也可以直接build在peer里面)
这里介绍直接build的peer里面的办法。
- 参考已有的system chaincode
cp -r core/scc/qscc core/scc/myscc
把qscc拷贝一份,作为例子直接在上面改了,然后简化实现:PUT和GET两个操作:
$ cat core/scc/myscc/myscc.go
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package myscc
import (
"fmt"
"github.com/hyperledger/fabric/common/flogging"
"github.com/hyperledger/fabric/core/aclmgmt"
"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(aclProvider aclmgmt.ACLProvider) *MySccImp {
return &MySccImp{
aclProvider: aclProvider,
}
}
func (e *MySccImp) Name() string { return "myscc" }
func (e *MySccImp) Path() string { return "github.com/hyperledger/fabric/core/scc/myscc" }
func (e *MySccImp) InitArgs() [][]byte { return nil }
func (e *MySccImp) Chaincode() shim.Chaincode { return e }
func (e *MySccImp) InvokableExternal() bool { return true }
func (e *MySccImp) InvokableCC2CC() bool { return true }
func (e *MySccImp) Enabled() bool { return true }
// MySccImp implements the ledger query functions, including:
// - Add add a record
// - Query query a record
type MySccImp struct {
aclProvider aclmgmt.ACLProvider
}
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)
}
- 然后注册进去peer:
$ diff --git a/src/github.com/hyperledger/fabric/peer/node/start.go b/src/github.com/hyperledger/fabric/peer/node/start.go
index eae5f3c..ee3228d 100644
--- a/src/github.com/hyperledger/fabric/peer/node/start.go
+++ b/src/github.com/hyperledger/fabric/peer/node/start.go
@@ -69,6 +69,7 @@ import (
"github.com/hyperledger/fabric/core/scc/cscc"
"github.com/hyperledger/fabric/core/scc/lscc"
"github.com/hyperledger/fabric/core/scc/qscc"
+ "github.com/hyperledger/fabric/core/scc/myscc"
"github.com/hyperledger/fabric/discovery"
"github.com/hyperledger/fabric/discovery/endorsement"
discsupport "github.com/hyperledger/fabric/discovery/support"
@@ -748,10 +749,11 @@ func registerChaincodeSupport(
csccInst := cscc.New(ccp, sccp, aclProvider)
qsccInst := qscc.New(aclProvider)
+ mysccInst := myscc.New(aclProvider)
//Now that chaincode is initialized, register all system chaincodes.
sccs := scc.CreatePluginSysCCs(sccp)
- for _, cc := range append([]scc.SelfDescribingSysCC{lsccInst, csccInst, qsccInst, lifecycleSCC}, sccs...) {
+ for _, cc := range append([]scc.SelfDescribingSysCC{lsccInst, csccInst, qsccInst, mysccInst, lifecycleSCC}, sccs...) {
sccp.RegisterSysCC(cc)
}
就是参考qscc的类似,一样实现就行了。
注意这里看到New函数创建system chaincode实例的时候传入了一个aclProvider,但是在myscc里面并没有使用,丢掉了,后面可以再加强。
-
重新build peer executable
-
修改core.yaml文件
把myscc添加到system chaincode的whitelist里面
# 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
- 重启peer就可以了
用命令行调用新的system chaincode:
$ peer chaincode invoke -C "<channel>" -n "myscc" -c '{"Args":["Put", "a", "aaa"]}'
$ peer chaincode invoke -C "<channel>" -n "myscc" -c '{"Args":["Get", "a"]}'
当然要先把peer加入到<channel>里面。
注意system chaincode并没有install, instantiate的操作,所以也不存在system chaincode属于哪一个channel的问题,在chaincode主函数Invoke的参数stub指向的就是从命令行中"-C"所传递的channel。
网友评论