fabric1.4如何开发实现system chaincode

2020-08-14  本文已影响0人  CodingCode

这篇文章介绍如何在fabric1.4里面实现一个system chaincode的例子。
(实现一个system chaincode的例子可以用插件(在fabric1.4版本中缺省情况下已经被禁用了),也可以直接build在peer里面)

这里介绍直接build的peer里面的办法。

  1. 参考已有的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)
}
  1. 然后注册进去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里面并没有使用,丢掉了,后面可以再加强。

  1. 重新build peer executable

  2. 修改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
  1. 重启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。

上一篇下一篇

猜你喜欢

热点阅读