Is it possible to use gRPC in hyperledger-chaincode and if so, how can I avoid errors during invocation on test-network?

138 Views Asked by At

I want to use gRPC in fabric chaincode to achieve cross-chain communcation instead of using fabric SDK. But when I invoke chaincode function on fabric-sample/test-network, it always occurs errors.

Error: endorsement failure during invoke. response: status:500 message:"error in simulation: failed to execute transaction eb5e480bd4075a767f56ae263741ca0f5f19620ef88952e26b7f1952bdbe83cd: could not launch chaincode chaincode_1.2:d3f97f15a635e73d3de230c8e5899e5fb95a68cf897c03e19f9e4eeca7ca3fd5: chaincode registration failed: container exited with 2"

Who can tell me what cause this error? My chaincode has bug or gRPC cannot be used in chaincode function?

my chaincode about gRPC:

func (s *SmartContract) begin(ctx contractapi.TransactionContextInterface) error {
    server.Main()
    return nil
}

func (s *SmartContract) client(ctx contractapi.TransactionContextInterface) error {
    // client.Clientfunc is the client main function
    client.Clientfunc(Xt, R, sign, m)
}

server.go

func Main() {
    listen, err := net.Listen("tcp", ":9090")
    if err != nil {
        fmt.Printf("failed to listen: %v", err)
        return
    }
    grpcServer := grpc.NewServer()
    pb.RegisterSendServiceServer(grpcServer, &server{})
    err2 := grpcServer.Serve(listen)
    if err2 != nil {
        fmt.Printf("failed to serve: %v", err2)
        return
    }
}

client.go

func Clientfunc(Xt *btcec.PublicKey, R *btcec.PublicKey, s *big.Int, m []byte) []byte {
    conn, err := grpc.Dial("127.0.0.1:9090", grpc.WithTransportCredentials(insecure.NewCredentials()))
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    client := pb.NewSendServiceClient(conn)
    output := &pb.SignInput{
        XtX: Xt.X().Int64(),
        XtY: Xt.Y().Int64(),
        M:   m,
        RX:  R.X().Int64(),
        RY:  R.Y().Int64(),
        S:   s.Int64(),
    }
    resp, _ := client.Send(context.Background(), output)
    return resp.GetM()
}
1

There are 1 best solutions below

6
VonC On BEST ANSWER

Who can tell me what cause this error?

As detailed in Hyperledger Fabric v2.x/ Logging Control, what can tell you what caused an error 500 (internal server error) are the server logs

Depending on how you are running it:

docker logs <chaincode_container_id>
kubectl logs -n <namespace> <pod_name>
oc logs -n <namespace> <pod_name>

It could be due to a problem in your chaincode (like a bug in the gRPC code), or it could be due to the environment in which the chaincode is running.


From your code, you might consider not starting the gRPC server (server.Main()) in the chaincode. Chaincode runs within the Hyperledger Fabric network and is not meant to handle network communications like a standalone application does.
Instead, you should make the gRPC server a separate service that runs independently, and then the chaincode can communicate with this service as needed.

Plus the client.Clientfunc() function seems to establish a gRPC connection, send a request, and wait for a response. This is a synchronous operation and can be problematic if the response takes a long time to arrive. It's better to use an asynchronous operation (i.e., send the request and handle the response in a callback function) to avoid blocking the chaincode execution.
And... you should not ignore the error from client.Send() ;)

Make sure your gRPC server does not require secure connections, or a grpc.WithTransportCredentials(insecure.NewCredentials()) (insecure connection without SSL/TLS) will fail.


Typically, it's advisable to handle communication with external systems (like via gRPC) in the Fabric client application, not within the chaincode itself.

If I just want to use chaincode instead of fabric application, is there any way to communicate between orgs of different channels?

Communication between organizations on different channels can be complex, as it is a fundamental aspect of Hyperledger Fabric's design that channels are isolated from one another to maintain data privacy.

You might consider:

  • Chaincode Functions: One organization can invoke a chaincode function on its own channel, which in turn invokes a chaincode function on another channel. This is possible because a chaincode can be associated with multiple channels.
    Note that this approach has the limitation that the second function invocation is not part of the same transaction as the first, so it can't be rolled back if the first transaction fails.

  • Dual Membership: An organization can be part of multiple channels. Therefore, it can read data from one channel and write data to another channel. However, this is done in two separate transactions, so atomicity cannot be guaranteed.

  • Private Data Collections (PDCs): If the goal is to share private data between specific organizations, even across different channels, PDCs might be an option. A PDC allows a defined subset of organizations on a channel to endorse, commit, or query private data without distributing the data across all the organizations on the channel.

  • Interoperability Solutions: There are also more advanced solutions being developed for blockchain interoperability, like the Interledger Protocol (ILP), that could potentially be used to move data or assets between different Fabric networks (or even between entirely different types of blockchain networks).
    However, these are still largely in the research and development stage and might not be ready for production use.