2

我正在使用 fabric-sdk-go 来安装、实例化、调用和查询链代码。

  1. 链码安装成功。

    root@991bc7577959:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode list --installed
    Get installed chaincodes on peer:
     Name: myproject, Version: 1.0, Path: github.com/hyperledger/myproject/chaincode/, Id: 130607a18ab3fe332854d7c2048f04b89e3c740e1ffa97c76c9ced266e6714ca
    
  2. 链码实例化。

    代码片段

    ccPolicy := cauthdsl.SignedByAnyMember([]string{"Seller", "Buyer"})
    fmt.Println("Value of ccPolicy is: ", ccPolicy)
    resp, err := setup.admin.InstantiateCC(setup.ChannelID, 
    resmgmt.InstantiateCCRequest{
        Name:    setup.ChainCodeID,
        Path:    setup.ChaincodeGoPath,
        Version: "1.0",
        Args:    [][]byte{[]byte("init"), []byte("Seller"), []byte("100"), []byte("Buyer"), []byte("200")},
        Policy: ccPolicy,
    })    
    
检查 docker 容器
root@991bc7577959:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode list --instantiated -C mychannel
 Get instantiated chaincodes on channel mychannel:
   Name: myproject, Version: 1.0, Path: github.com/hyperledger/myproject/chaincode/, Input: <nil>, Escc: escc, Vscc: vscc

这里链码被实例化,但 Input 标签显示 nil 值。是预期的吗?不是应该显示我用于实例化的值吗

  1. 查询链码

    代码片段

    func (setup *FabricSetup) Query(OrgName string) (string, error) {
        fmt.Println("\n Calling query method")
        // Prepare arguments
        var args []string
        args = append(args, OrgName)
        response, err := setup.client.Query(channel.Request{
            ChaincodeID: setup.ChainCodeID,
            Fcn:         "invoke",
            Args:        [][]byte{[]byte("query"), []byte(args[0])}})
        if err != nil {
            return "", fmt.Errorf("failed to query: %v", err)
        }
    
        fmt.Println("\n Query chaincode ended")
        return string(response.Payload), err
    }   
    

对链码的这种查询导致以下错误:

恐慌:运行时错误:无效的内存地址或零指针取消引用

【信号SIGSEGV:分段违规代码=0x1 addr=0x8 pc=0x9e17e0】

goroutine 1 [运行]:github.com/hyperledger/fabric-sdk-go/pkg/client/channel.(*Client).Query(0x0, 0xdb43d4, 0x9, 0xdb14ef, 0x6, 0xc00016ff80, 0x2, 0x2, 0x0, 0x0 , ...) /home/alpha/GoWorkspace/src/github.com/hyperledger/fabric-sdk-go/pkg/client/channel/chclient.go:97 +0xc0 github.com/hyperledger/myproject/sdk.( *FabricSetup).Query(0xc000179ea8, 0xdb0f3d, 0x6, 0x0, 0xdbbe50, 0x13, 0xdb43cb) >/home/alpha/GoWorkspace/src/github.com/hyperledger/myproject/sdk/query.go:17 +0x2d4 main.main () /c/Projects/Go/src/github.com/hyperledger/myproject/main.go:79 +0x176

setup.go:用于创建通道、安装和实例化链码的文件

import packages
type FabricSetup struct {
    ConfigFile      string
    OrgID           string
    OrdererID       string
    ChannelID       string
    ChainCodeID     string
    initialized     bool
    ChannelConfig   string
    ChaincodeGoPath string
    ChaincodePath   string
    OrgAdmin        string
    OrgName         string
    UserName        string
    client          *channel.Client
    admin           *resmgmt.Client
    adminIdentity   *msp.SigningIdentity
    sdk             *fabsdk.FabricSDK
    event           *event.Client
}

// Initialize reads the configuration file and sets up the client, chain and event hub
func (setup *FabricSetup) Initialize() error {
    // Step 1: creates the channel and updates all of the anchor peers for all orgs
    identityManagerClientContext := setup.sdk.Context(fabsdk.WithUser(setup.OrgAdmin), fabsdk.WithOrg(setup.OrgName))
    if err != nil {
        return errors.WithMessage(err, "failed to load Admin identity")
    }

    fmt.Printf("\n Step 2.a: Value of identityManagerClientContext is: ", identityManagerClientContext)

    // Channel management client is responsible for managing channels (create/update channel)
    chMgmtClient, err := resmgmt.New(identityManagerClientContext)
    if err != nil {
        return errors.WithMessage(err, "failed to create channel management client from Admin identity")
    }

    setup.admin = chMgmtClient
    mspClient, err := mspclient.New(setup.sdk.Context(), mspclient.WithOrg(setup.OrgName))
    if err != nil {
        return errors.WithMessage(err, "failed to create MSP client")
    }
    adminIdentity, err := mspClient.GetSigningIdentity(setup.OrgAdmin)
    if err != nil {
        return errors.WithMessage(err, "failed to get admin signing identity")
    }
    setup.adminIdentity = &adminIdentity
    fmt.Println("Initialization Successful")
    setup.initialized = true
    return nil
}

// CreateChannel for creating channel between the Organizations
func (setup *FabricSetup) CreateChannel() error {

    req := resmgmt.SaveChannelRequest{
        ChannelID:         setup.ChannelID,
        ChannelConfigPath: setup.ChannelConfig,
        SigningIdentities: []msp.SigningIdentity{*setup.adminIdentity},
    }
    txID, err := setup.admin.SaveChannel(req, resmgmt.WithOrdererEndpoint(setup.OrdererID))
    if err != nil || txID.TransactionID == "" {
        return errors.WithMessage(err, "failed to save channel")
    }
    fmt.Println("Channel created")
    return nil
}

// joins all peers in all of the given orgs to the given channel
func (setup *FabricSetup) JoinChannel() error {
    // Make admin user join the previously created channel
    if err := setup.admin.JoinChannel(
        setup.ChannelID,
        resmgmt.WithRetry(retry.DefaultResMgmtOpts),
        resmgmt.WithOrdererEndpoint(setup.OrdererID)); err != nil {
        return errors.WithMessage(err, "failed to make admin join channel")
    }
    fmt.Println("Channel joined")
    return nil
}

// InstallCC to install and instantiate the chaincode
func (setup *FabricSetup) InstallCC() error {

    // Create the chaincode package that will be sent to the peers
    ccPkg, err := packager.NewCCPackage(setup.ChaincodePath, setup.ChaincodeGoPath)
    if err != nil {
        return errors.WithMessage(err, "failed to create chaincode package")
    }
    fmt.Println("ccPkg created")

    // Install example cc to org peers
    installCCReq := resmgmt.InstallCCRequest{
        Name:    setup.ChainCodeID,
        Path:    setup.ChaincodePath,
        Version: "1.0", //chaincode version. first version of chaincode
        Package: ccPkg,
    }
    _, err = setup.admin.InstallCC(installCCReq, resmgmt.WithRetry(retry.DefaultResMgmtOpts))
    if err != nil {
        return errors.WithMessage(err, "failed to install chaincode")
    }
    fmt.Println("Chaincode installed")
    return nil
}

// InstantiateCC for instantiating the chaincode
func (setup *FabricSetup) InstantiateCC() error {
    // Set up chaincode policy
    ccPolicy := cauthdsl.SignedByAnyMember([]string{"Seller", "Buyer"})
    fmt.Println("Value of ccPolicy is: ", ccPolicy)

    resp, err := setup.admin.InstantiateCC(setup.ChannelID, resmgmt.InstantiateCCRequest{
        Name:    setup.ChainCodeID,
        Path:    setup.ChaincodeGoPath,
        Version: "1.0",
        Args:    [][]byte{[]byte("init"), []byte("Seller"), []byte("100"), []byte("Buyer"), []byte("200")},
        //Args:   [][]byte{[]byte("init")},
        Policy: ccPolicy,
    })
    if err != nil || resp.TransactionID == "" {
        return errors.WithMessage(err, "failed to instantiate the chaincode")
    }
    fmt.Println("Chaincode instantiated")

    // Channel client is used to query and execute transactions
    clientContext := setup.sdk.ChannelContext(setup.ChannelID, fabsdk.WithUser(setup.UserName))
    setup.client, err = channel.New(clientContext)
    if err != nil {
        return errors.WithMessage(err, "failed to create new channel client")
    }
    fmt.Println("Channel client created")

    // Creation of the client which will enables access to our channel events
    setup.event, err = event.New(clientContext)
    if err != nil {
        return errors.WithMessage(err, "failed to create new event client")
    }
    fmt.Println("Event client created")

    fmt.Println("Chaincode Installation & Instantiation Successful")
    return nil
}

// CloseSDK to close the sdk connection
func (setup *FabricSetup) CloseSDK() {
    setup.sdk.Close()
}

  1. main.go 文件:调用该文件中的所有方法

    func initializeChannelAndCC(fSetup sdk.FabricSetup) {
        err := fSetup.CreateChannel()
        if err != nil {
            fmt.Printf("Unable to create channel: %v\n", err)
        }
        err = fSetup.JoinChannel()
        if err != nil {
            fmt.Printf("Unable to join channel: %v\n", err)
        }
        err = fSetup.InstallCC()
        if err != nil {
            fmt.Printf("Unable to install the chaincode: %v\n", err)
        }
        err = fSetup.InstantiateCC()
        if err != nil {
            fmt.Printf("Unable to instantiate the chaincode: %v\n", err)
        }
    }
    
    func main() {
        fSetup := sdk.FabricSetup{
            OrdererID: "orderer.mytrade.com",
            ChannelID:     "mychannel",
            ChannelConfig: "/c/Projects/Go/src/github.com/hyperledger/myproject/network/channel-artifacts/channel.tx",
            ChainCodeID:     "myproject",
            ChaincodeGoPath: "/c/Projects/Go",
            ChaincodePath:   "github.com/hyperledger/myproject/chaincode/",
            OrgAdmin:        "Admin",
            OrgName:         "Seller",
            ConfigFile:      "config.yaml",
            UserName: "User1",
        }
    
        err := fSetup.Initialize()
        if err != nil {
            fmt.Printf("Unable to initialize the Fabric SDK: %v\n", err)
            return
        }
        defer fSetup.CloseSDK()
        initializeChannelAndCC(fSetup)
        response, err := fSetup.Query("Seller")
        if err != nil {
            fmt.Printf("Unable to query the chaincode: %v\n", err)
        } else {
            fmt.Printf("Response from the query: %s\n", response)
        }
    }
    

客户端日志记录(设置为调试模式)。这些日志很大,因此共享链接ClientLogs

请帮忙。

编辑:添加链码

type SimpleChaincode struct {
}

// Init method: one time initialisation
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
    fmt.Println("ex02 Init")
    _, args := stub.GetFunctionAndParameters()
    var A, B string    // Entities
    var Aval, Bval int // Asset holdings
    var err error

    if len(args) != 4 {
        return shim.Error("Incorrect number of arguments. Expecting 4")
    }

    test := strings.Join(args, ", ")
    fmt.Println("Value of args is: ", test)

    // Initialize the chaincode
    A = args[0]
    Aval, err = strconv.Atoi(args[1])
    if err != nil {
        return shim.Error("Expecting integer value for asset holding")
    }
    B = args[2]
    Bval, err = strconv.Atoi(args[3])
    if err != nil {
        return shim.Error("Expecting integer value for asset holding")
    }
    fmt.Printf("A = %s, Aval = %d, B = %s, Bval = %d\n", A, Aval, B, Bval)

    // Write the state to the ledger
    err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
    if err != nil {
        return shim.Error(err.Error())
    }

    err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
    if err != nil {
        return shim.Error(err.Error())
    }

    return shim.Success(nil)
}

// Invoke method: used to sedn the request to the various custom methods
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    fmt.Println("ex02 Invoke")
    function, args := stub.GetFunctionAndParameters()
    if function == "invoke" {
        // Make payment of X units from A to B
        return t.invoke(stub, args)
    } else if function == "delete" {
        // Deletes an entity from its state
        return t.delete(stub, args)
    } else if function == "query" {
        // the old "Query" is now implemtned in invoke
        return t.query(stub, args)
    }

    return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
}

// Transaction makes payment of X units from A to B
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    var A, B string    // Entities
    var Aval, Bval int // Asset holdings
    var X int          // Transaction value
    var err error

    fmt.Println("Value of args in invoke is: ", strings.Join(args, ", "))
    if len(args) != 3 {
        return shim.Error("Incorrect number of arguments. Expecting 3")
    }

    A = args[0]
    B = args[1]

    // Get the state from the ledger
    // TODO: will be nice to have a GetAllState call to ledger
    Avalbytes, err := stub.GetState(A)
    if err != nil {
        return shim.Error("Failed to get state")
    }
    if Avalbytes == nil {
        return shim.Error("Entity not found")
    }
    Aval, _ = strconv.Atoi(string(Avalbytes))

    Bvalbytes, err := stub.GetState(B)
    if err != nil {
        return shim.Error("Failed to get state")
    }
    if Bvalbytes == nil {
        return shim.Error("Entity not found")
    }
    Bval, _ = strconv.Atoi(string(Bvalbytes))

    // Perform the execution
    X, err = strconv.Atoi(args[2])
    if err != nil {
        return shim.Error("Invalid transaction amount, expecting a integer value")
    }
    Aval = Aval - X
    Bval = Bval + X
    fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

    // Write the state back to the ledger
    err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
    if err != nil {
        return shim.Error(err.Error())
    }

    err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
    if err != nil {
        return shim.Error(err.Error())
    }

    return shim.Success(nil)
}

// Deletes an entity from state
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    if len(args) != 1 {
        return shim.Error("Incorrect number of arguments. Expecting 1")
    }

    A := args[0]

    // Delete the key from the state in ledger
    err := stub.DelState(A)
    if err != nil {
        return shim.Error("Failed to delete state")
    }

    return shim.Success(nil)
}

// query callback representing the query of a chaincode
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    fmt.Println("Inside query method")
    var A string // Entities
    var err error

    fmt.Println("\value of args in query method is: ", strings.Join(args, ", "))
    if len(args) != 1 {
        return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
    }

    A = args[0]

    // Get the state from the ledger
    Avalbytes, err := stub.GetState(A)
    if err != nil {
        jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
        return shim.Error(jsonResp)
    }

    if Avalbytes == nil {
        jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
        return shim.Error(jsonResp)
    }

    jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
    fmt.Printf("Query Response:%s\n", jsonResp)
    return shim.Success(Avalbytes)
}

func main() {
    err := shim.Start(new(SimpleChaincode))
    if err != nil {
        fmt.Printf("Error starting Simple chaincode: %s", err)
    }
}

编辑

  1. 在运行时错误之后,我使用命令登录到peer0.seller.mytrade.comcli docker exec -it cli bash并运行peer chaincode query -C mychannel -n myproject -c '{"Args":["query","Seller"]}'命令来查询链码,我得到了结果Seller = 100

  2. 在运行peer chaincode query命令之前,dev-peer0.seller.mytrade.com容器丢失了。只有容器dev-peer1.seller.mytrade.com存在。但是 在cli上的peer chaincode query命令导致链码容器之后。peer0.seller.mytrade.com由于在卖方的两个对等方上调用了链码,因此两个容器都应该在那里。

  3. 我还添加了 20 秒的延迟,因为我认为 docker 需要一些时间来创建容器。但它没有用。

  4. PFAdocker ps -a命令 的图像docker ps -a 输出

4

0 回答 0