diff --git a/ecc_go/chaincode/enclave_go/enclave.go b/ecc_go/chaincode/enclave_go/enclave.go index 04545d894..3b25a8729 100644 --- a/ecc_go/chaincode/enclave_go/enclave.go +++ b/ecc_go/chaincode/enclave_go/enclave.go @@ -18,6 +18,7 @@ import ( "github.com/hyperledger/fabric-private-chaincode/ecc_go/chaincode/enclave_go/attestation" "github.com/hyperledger/fabric-private-chaincode/internal/crypto" "github.com/hyperledger/fabric-private-chaincode/internal/protos" + pb "github.com/hyperledger/fabric-protos-go/peer" "github.com/hyperledger/fabric/bccsp" "github.com/hyperledger/fabric/bccsp/factory" "github.com/hyperledger/fabric/common/flogging" @@ -37,6 +38,7 @@ type EnclaveStub struct { hostParams *protos.HostParameters chaincodeParams *protos.CCParameters fabricCryptoProvider bccsp.BCCSP + stubProvider func(shim.ChaincodeStubInterface, *pb.ChaincodeInput, *readWriteSet, StateEncryptionFunctions) shim.ChaincodeStubInterface } func NewEnclaveStub(cc shim.Chaincode) *EnclaveStub { @@ -49,6 +51,9 @@ func NewEnclaveStub(cc shim.Chaincode) *EnclaveStub { csp: crypto.GetDefaultCSP(), ccRef: cc, fabricCryptoProvider: cryptoProvider, + stubProvider: func(stub shim.ChaincodeStubInterface, input *pb.ChaincodeInput, rwset *readWriteSet, sep StateEncryptionFunctions) shim.ChaincodeStubInterface { + return NewFpcStubInterface(stub, input, rwset, sep) + }, } } @@ -161,7 +166,7 @@ func (e *EnclaveStub) ChaincodeInvoke(stub shim.ChaincodeStubInterface, chaincod // Invoke chaincode // we wrap the stub with our FpcStubInterface - fpcStub := NewFpcStubInterface(stub, cleartextChaincodeRequest.GetInput(), rwset, e.ccKeys) + fpcStub := e.stubProvider(stub, cleartextChaincodeRequest.GetInput(), rwset, e.ccKeys) ccResponse := e.ccRef.Invoke(fpcStub) // marshal chaincode response diff --git a/ecc_go/chaincode/enclave_go/skvs_stub.go b/ecc_go/chaincode/enclave_go/skvs_stub.go new file mode 100644 index 000000000..3a07ce196 --- /dev/null +++ b/ecc_go/chaincode/enclave_go/skvs_stub.go @@ -0,0 +1,20 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package enclave_go + +import ( + "github.com/hyperledger/fabric-chaincode-go/shim" + pb "github.com/hyperledger/fabric-protos-go/peer" +) + +func NewSkvsStub(cc shim.Chaincode) *EnclaveStub { + enclaveStub := NewEnclaveStub(cc) + enclaveStub.stubProvider = func(stub shim.ChaincodeStubInterface, input *pb.ChaincodeInput, rwset *readWriteSet, sep StateEncryptionFunctions) shim.ChaincodeStubInterface { + return NewSkvsStubInterface(stub, input, rwset, sep) + } + return enclaveStub +} diff --git a/ecc_go/chaincode/enclave_go/skvs_stub_interface.go b/ecc_go/chaincode/enclave_go/skvs_stub_interface.go new file mode 100644 index 000000000..6c45be1a3 --- /dev/null +++ b/ecc_go/chaincode/enclave_go/skvs_stub_interface.go @@ -0,0 +1,117 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package enclave_go + +import ( + "encoding/json" + "fmt" + + "github.com/hyperledger/fabric-chaincode-go/shim" + pb "github.com/hyperledger/fabric-protos-go/peer" +) + +const SKVSKey = "SKVS" + +type SkvsStubInterface struct { + *FpcStubInterface + allDataOld map[string][]byte + allDataNew map[string][]byte + key string +} + +func NewSkvsStubInterface(stub shim.ChaincodeStubInterface, input *pb.ChaincodeInput, rwset *readWriteSet, sep StateEncryptionFunctions) *SkvsStubInterface { + fpcStub := NewFpcStubInterface(stub, input, rwset, sep) + skvsStub := &SkvsStubInterface{ + FpcStubInterface: fpcStub, + allDataOld: make(map[string][]byte), + allDataNew: make(map[string][]byte), + key: SKVSKey, + } + err := skvsStub.initSKVS() + if err != nil { + panic(fmt.Sprintf("Initializing SKVS failed, err: %v", err)) + } + return skvsStub +} + +func (s *SkvsStubInterface) initSKVS() error { + + // get current state, this will only operate once + encValue, err := s.GetPublicState(s.key) + if err != nil { + return err + } + + // return if the key initially does not exist + if len(encValue) == 0 { + logger.Warningf("SKVS is empty, Initiating.") + return nil + } + + value, err := s.sep.DecryptState(encValue) + if err != nil { + return err + } + logger.Debug("SKVS has default value, loading current value.") + + err = json.Unmarshal(value, &s.allDataOld) + if err != nil { + logger.Errorf("SKVS Json unmarshal error: %s", err) + return err + } + err = json.Unmarshal(value, &s.allDataNew) + if err != nil { + logger.Errorf("SKVS Json unmarshal error: %s", err) + return err + } + return nil +} + +func (s *SkvsStubInterface) GetState(key string) ([]byte, error) { + value, found := s.allDataOld[key] + if !found { + logger.Errorf("skvs allDataOld key: %s, not found", key) + return nil, nil + } + return value, nil +} + +func (s *SkvsStubInterface) PutState(key string, value []byte) error { + + s.allDataNew[key] = value + byteAllData, err := json.Marshal(s.allDataNew) + if err != nil { + return err + } + encValue, err := s.sep.EncryptState(byteAllData) + if err != nil { + return err + } + + return s.PutPublicState(s.key, encValue) +} + +func (s *SkvsStubInterface) DelState(key string) error { + delete(s.allDataNew, key) + byteAllData, err := json.Marshal(s.allDataNew) + if err != nil { + return err + } + encValue, err := s.sep.EncryptState(byteAllData) + if err != nil { + return err + } + return s.PutPublicState(s.key, encValue) +} + +func (s *SkvsStubInterface) GetStateByRange(startKey string, endKey string) (shim.StateQueryIteratorInterface, error) { + panic("not implemented") // TODO: Implement +} + +func (s *SkvsStubInterface) GetStateByRangeWithPagination(startKey string, endKey string, pageSize int32, bookmark string) (shim.StateQueryIteratorInterface, *pb.QueryResponseMetadata, error) { + panic("not implemented") // TODO: Implement +} diff --git a/ecc_go/chaincode/private.go b/ecc_go/chaincode/private.go index d880cc474..6773f313e 100644 --- a/ecc_go/chaincode/private.go +++ b/ecc_go/chaincode/private.go @@ -14,14 +14,24 @@ import ( "github.com/hyperledger/fabric-private-chaincode/internal/endorsement" ) +type BuildOption func(*chaincode.EnclaveChaincode, shim.Chaincode) + // NewPrivateChaincode creates a new chaincode! This is for go support only!!! -func NewPrivateChaincode(cc shim.Chaincode) *chaincode.EnclaveChaincode { +func NewPrivateChaincode(cc shim.Chaincode, options ...BuildOption) *chaincode.EnclaveChaincode { ecc := &chaincode.EnclaveChaincode{ Enclave: enclave_go.NewEnclaveStub(cc), Validator: endorsement.NewValidator(), Extractor: &chaincode.ExtractorImpl{}, Ercc: &ercc.StubImpl{}, } - + for _, o := range options { + o(ecc, cc) + } return ecc } + +func WithSKVS() BuildOption { + return func(ecc *chaincode.EnclaveChaincode, cc shim.Chaincode) { + ecc.Enclave = enclave_go.NewSkvsStub(cc) + } +} diff --git a/samples/chaincode/secret-keeper-go/Makefile b/samples/chaincode/secret-keeper-go/Makefile index 8f80af00d..a9f56395b 100644 --- a/samples/chaincode/secret-keeper-go/Makefile +++ b/samples/chaincode/secret-keeper-go/Makefile @@ -4,6 +4,13 @@ # SPDX-License-Identifier: Apache-2.0 TOP = ../../.. -include $(TOP)/ecc_go/build.mk CC_NAME ?= fpc-secret-keeper-go + +# Define paths for cmd subdirectories +DEFAULT= cmd/naive/main.go +SKVS_PATH = cmd/skvs/main.go + +ECC_MAIN_FILES ?=$(DEFAULT) + +include $(TOP)/ecc_go/build.mk diff --git a/samples/chaincode/secret-keeper-go/main.go b/samples/chaincode/secret-keeper-go/cmd/naive/main.go similarity index 100% rename from samples/chaincode/secret-keeper-go/main.go rename to samples/chaincode/secret-keeper-go/cmd/naive/main.go diff --git a/samples/chaincode/secret-keeper-go/cmd/skvs/main.go b/samples/chaincode/secret-keeper-go/cmd/skvs/main.go new file mode 100644 index 000000000..d9808f78b --- /dev/null +++ b/samples/chaincode/secret-keeper-go/cmd/skvs/main.go @@ -0,0 +1,41 @@ +/* +Copyright IBM Corp. All Rights Reserved. +Copyright 2020 Intel Corporation + +SPDX-License-Identifier: Apache-2.0 +*/ + +package main + +import ( + "os" + + "github.com/hyperledger/fabric-chaincode-go/shim" + "github.com/hyperledger/fabric-contract-api-go/contractapi" + fpc "github.com/hyperledger/fabric-private-chaincode/ecc_go/chaincode" + "github.com/hyperledger/fabric-private-chaincode/samples/chaincode/secret-keeper-go/chaincode" +) + +func main() { + + ccid := os.Getenv("CHAINCODE_PKG_ID") + addr := os.Getenv("CHAINCODE_SERVER_ADDRESS") + + // create chaincode + secretChaincode, _ := contractapi.NewChaincode(&chaincode.SecretKeeper{}) + skvsChaincode := fpc.NewPrivateChaincode(secretChaincode, fpc.WithSKVS()) + + // start chaincode as a service + server := &shim.ChaincodeServer{ + CCID: ccid, + Address: addr, + CC: skvsChaincode, + TLSProps: shim.TLSProperties{ + Disabled: true, // just for testing good enough + }, + } + + if err := server.Start(); err != nil { + panic(err) + } +}