Skip to content

Commit

Permalink
Add initial client go sdk prototype
Browse files Browse the repository at this point in the history
- initial go sdk extension for FPC that hides the FPC transaction flow
  from the user
- integrate with test-network

Signed-off-by: bur <[email protected]>
  • Loading branch information
mbrandenburger committed Oct 27, 2020
1 parent fdccf21 commit e2dd849
Show file tree
Hide file tree
Showing 9 changed files with 561 additions and 2 deletions.
20 changes: 20 additions & 0 deletions client_sdk/go/fpc/attestation/transformation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package attestation

import (
"log"

"github.com/hyperledger-labs/fabric-private-chaincode/internal/protos"
)

func ToEvidence(credentials *protos.Credentials) (*protos.Credentials, error) {

// do something
log.Printf("Perform attestation to evidence transformation\n")

// TODO call brunos attestation_to_evidence.sh
// call $FPC_PATH/common/crypto/attestation-api/conversion/attestation_to_evidence.sh

credentials.Evidence = credentials.Attestation

return credentials, nil
}
154 changes: 154 additions & 0 deletions client_sdk/go/fpc/contract.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
Copyright 2020 IBM All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package fpc

import (
"encoding/base64"
"encoding/json"
"log"

"github.com/hyperledger-labs/fabric-private-chaincode/internal/utils"
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
"github.com/hyperledger/fabric-sdk-go/pkg/gateway"
"github.com/pkg/errors"
)

type ContractInterface interface {
ManagementInterface
Name() string
EvaluateTransaction(name string, args ...string) ([]byte, error)
SubmitTransaction(name string, args ...string) ([]byte, error)
//CreateTransaction(name string, opts ...gateway.TransactionOption) (*gateway.Transaction, error)
RegisterEvent(eventFilter string) (fab.Registration, <-chan *fab.CCEvent, error)
Unregister(registration fab.Registration)
}

func GetContract(network *gateway.Network, chaincodeId string) ContractInterface {
contract := network.GetContract(chaincodeId)
ercc := network.GetContract("ercc")
return &Contract{contract, ercc, nil}
}

type Contract struct {
contract *gateway.Contract
ercc *gateway.Contract
cachedChaincodeEncryptionKey []byte
}

func (c *Contract) Name() string {
return c.contract.Name()
}

func (c *Contract) getChaincodeEncryptionKey() ([]byte, error) {
if c.cachedChaincodeEncryptionKey == nil {
ccKeyBytes, err := c.ercc.EvaluateTransaction("queryChaincodeEncryptionKey", c.Name())
if err != nil {
return nil, err
}
c.cachedChaincodeEncryptionKey = ccKeyBytes
}
return c.cachedChaincodeEncryptionKey, nil
}

func (c *Contract) prepareChaincodeInvocation(name string, args []string, resultEncryptionKey []byte) (string, error) {
p := &utils.ChaincodeParams{
Function: name,
Args: args,
ResultEncryptionKey: resultEncryptionKey,
}

pBytes, err := json.Marshal(p)
if err != nil {
return "", err
}

log.Printf("prepping chaincode params: %s\n", p)

k, err := c.getChaincodeEncryptionKey()
if err != nil {
return "", err
}

encryptedParams, err := Encrypt(pBytes, k)
if err != nil {
return "", err
}

return base64.StdEncoding.EncodeToString(encryptedParams), nil
}

func (c *Contract) EvaluateTransaction(name string, args ...string) ([]byte, error) {

// pick response encryption key
resultEncryptionKey, err := KeyGen()
if err != nil {
return nil, err
}

encryptedParamsBase64, err := c.prepareChaincodeInvocation(name, args, resultEncryptionKey)
if err != nil {
return nil, err
}

log.Printf("calling __invoke!\n")
responseBytes, err := c.contract.EvaluateTransaction("__invoke", encryptedParamsBase64)
if err != nil {
return nil, err
}

response, err := utils.UnmarshalResponse(responseBytes)
if err != nil {
return nil, err
}

// decrypt result
return Decrypt(response.ResponseData, resultEncryptionKey)
}

func (c *Contract) SubmitTransaction(name string, args ...string) ([]byte, error) {

// pick response encryption key
resultEncryptionKey, err := KeyGen()
if err != nil {
return nil, err
}

encryptedParamsBase64, err := c.prepareChaincodeInvocation(name, args, resultEncryptionKey)
if err != nil {
return nil, err
}

log.Printf("calling __invoke!\n")

// first invoke (query) fpc chaincode
responseBytes, err := c.contract.EvaluateTransaction("__invoke", encryptedParamsBase64)
if err != nil {
return nil, errors.Wrap(err, "evaluation transaction failed")
}

log.Printf("calling __endorse!\n")
// next invoke chaincode endorsement
_, err = c.contract.SubmitTransaction("__endorse", base64.StdEncoding.EncodeToString(responseBytes))
if err != nil {
return nil, err
}

response, err := utils.UnmarshalResponse(responseBytes)
if err != nil {
return nil, err
}

return Decrypt(response.ResponseData, resultEncryptionKey)
}

func (c *Contract) RegisterEvent(eventFilter string) (fab.Registration, <-chan *fab.CCEvent, error) {
return c.contract.RegisterEvent(eventFilter)
}

func (c *Contract) Unregister(registration fab.Registration) {
c.contract.Unregister(registration)
}
13 changes: 13 additions & 0 deletions client_sdk/go/fpc/crypto.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package fpc

func Encrypt(input []byte, encryptionKey []byte) ([]byte, error) {
return input, nil
}

func KeyGen() ([]byte, error) {
return []byte("fake key"), nil
}

func Decrypt(encryptedResponse []byte, resultEncryptionKey []byte) ([]byte, error) {
return encryptedResponse, nil
}
61 changes: 61 additions & 0 deletions client_sdk/go/fpc/lifecycle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package fpc

import (
"encoding/base64"
"encoding/json"
"fmt"
"log"

"github.com/hyperledger-labs/fabric-private-chaincode/internal/utils"

"github.com/golang/protobuf/proto"
"github.com/hyperledger-labs/fabric-private-chaincode/client_sdk/go/fpc/attestation"
"github.com/hyperledger-labs/fabric-private-chaincode/internal/protos"
"github.com/hyperledger/fabric-sdk-go/pkg/gateway"
"github.com/hyperledger/fabric/protoutil"
)

type ManagementInterface interface {
CreateEnclave(attestationParams ...string) error
}

type ManagementAPI struct {
network *gateway.Network
}

func (c *Contract) CreateEnclave(attestationParams ...string) error {

p, err := json.Marshal(&utils.AttestationParams{Params: attestationParams})
attestationParamsBase64 := base64.StdEncoding.EncodeToString(p)

log.Printf("Prep attestation params: %s\n", attestationParamsBase64)

credentialsBytes, err := c.contract.EvaluateTransaction("__initEnclave", attestationParamsBase64)
if err != nil {
return fmt.Errorf("evaluation error: %s", err)
}

credentials := &protos.Credentials{}
err = proto.Unmarshal(credentialsBytes, credentials)
if err != nil {
return fmt.Errorf("cannot unmarshal credentials: %s", err)
}
log.Printf("Received credentials from enclave: %s\n", credentials)

// perform attestation evidence transformation
credentials, err = attestation.ToEvidence(credentials)
if err != nil {
return err
}

credentialsBytes = protoutil.MarshalOrPanic(credentials)
credentialsBase64 := base64.StdEncoding.EncodeToString(credentialsBytes)

log.Printf("Call registerEnclave at ERCC: %s\n", attestationParamsBase64)
_, err = c.ercc.SubmitTransaction("registerEnclave", credentialsBase64)
if err != nil {
return err
}

return nil
}
20 changes: 20 additions & 0 deletions client_sdk/go/test/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2019 Intel Corporation
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0

TOP = ../../..
include $(TOP)/build.mk

build:
$(GO) build

test:
$(GO) test $(GOTAGS) -v ./...

clean:
$(GO) clean
rm -rf keystore wallet

run:
$(GO) run .
Loading

0 comments on commit e2dd849

Please sign in to comment.