diff --git a/docs/docs/weaver/getting-started/enabling-weaver-network/fabric.md b/docs/docs/weaver/getting-started/enabling-weaver-network/fabric.md index 81c0543f4b..89e085696d 100644 --- a/docs/docs/weaver/getting-started/enabling-weaver-network/fabric.md +++ b/docs/docs/weaver/getting-started/enabling-weaver-network/fabric.md @@ -308,13 +308,12 @@ A Fabric network channel must share its security domain (or membership) configur const response = await MembershipManager.createLocalMembership( gateway, members, // list of all organization MSPIDs that are part of the channel - securityDomain, // name of the local network's security domain channelName, // Channel Name contractName // Fabric Interoperation Chaincode installation ID on the channel ) } catch (e) { // On error try updating local membership - const response = await MembershipManager.updateLocalMembership(gateway, members, securityDomain, channelName, contractName) + const response = await MembershipManager.updateLocalMembership(gateway, members, channelName, contractName) } ``` diff --git a/weaver/common/protos-js/build-protos.sh b/weaver/common/protos-js/build-protos.sh index 556e000112..38d4f93aa7 100755 --- a/weaver/common/protos-js/build-protos.sh +++ b/weaver/common/protos-js/build-protos.sh @@ -23,9 +23,9 @@ grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR - # Typescript Build protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/common/interop_payload.proto $PROTOSDIR/common/asset_locks.proto $PROTOSDIR/common/asset_transfer.proto $PROTOSDIR/common/ack.proto $PROTOSDIR/common/query.proto $PROTOSDIR/common/state.proto $PROTOSDIR/common/proofs.proto $PROTOSDIR/common/verification_policy.proto $PROTOSDIR/common/membership.proto $PROTOSDIR/common/access_control.proto $PROTOSDIR/common/events.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/corda/view_data.proto -protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/driver/driver.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=grpc_js:$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/driver/driver.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/fabric/view_data.proto -protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/identity/agent.proto -protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/networks/networks.proto -protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=grpc_js:$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/identity/agent.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=grpc_js:$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/networks/networks.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=grpc_js:$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $FABRIC_PROTOSDIR/msp/identities.proto $FABRIC_PROTOSDIR/peer/proposal_response.proto $FABRIC_PROTOSDIR/peer/proposal.proto $FABRIC_PROTOSDIR/peer/chaincode.proto $FABRIC_PROTOSDIR/common/policies.proto $FABRIC_PROTOSDIR/msp/msp_principal.proto diff --git a/weaver/core/network/fabric-interop-cc/contracts/interop/membership.go b/weaver/core/network/fabric-interop-cc/contracts/interop/membership.go index bae0ec6d87..6ad8978f12 100644 --- a/weaver/core/network/fabric-interop-cc/contracts/interop/membership.go +++ b/weaver/core/network/fabric-interop-cc/contracts/interop/membership.go @@ -183,6 +183,7 @@ func (s *SmartContract) CreateLocalMembership(ctx contractapi.TransactionContext if err != nil { return fmt.Errorf("Unmarshal error: %s", err) } + membership.SecurityDomain = membershipLocalSecurityDomain membershipLocalKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membershipLocalSecurityDomain}) acp, getErr := ctx.GetStub().GetState(membershipLocalKey) @@ -220,6 +221,7 @@ func (s *SmartContract) UpdateLocalMembership(ctx contractapi.TransactionContext if err != nil { return fmt.Errorf("Unmarshal error: %s", err) } + membership.SecurityDomain = membershipLocalSecurityDomain membershipLocalKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membershipLocalSecurityDomain}) _, getErr := s.GetMembershipBySecurityDomain(ctx, membershipLocalSecurityDomain) diff --git a/weaver/docs/docs/external/getting-started/enabling-weaver-network/fabric.md b/weaver/docs/docs/external/getting-started/enabling-weaver-network/fabric.md index 3f5aad5a78..55b052d83c 100644 --- a/weaver/docs/docs/external/getting-started/enabling-weaver-network/fabric.md +++ b/weaver/docs/docs/external/getting-started/enabling-weaver-network/fabric.md @@ -304,13 +304,12 @@ A Fabric network channel must share its security domain (or membership) configur const response = await MembershipManager.createLocalMembership( gateway, members, // list of all organization MSPIDs that are part of the channel - securityDomain, // name of the local network's security domain channelName, // Channel Name contractName // Fabric Interoperation Chaincode installation ID on the channel ) } catch (e) { // On error try updating local membership - const response = await MembershipManager.updateLocalMembership(gateway, members, securityDomain, channelName, contractName) + const response = await MembershipManager.updateLocalMembership(gateway, members, channelName, contractName) } ``` - `` should be replaced with standard (boilerplate) code to get a handle to your network's gateway. This requires a special wallet identity, namely one with a `network-admin` attribute indicating that the caller is a trusted network administrator who is authorized to record local memberships on the `channelName` channel. diff --git a/weaver/samples/fabric/fabric-cli/src/helpers/interop-setup/configure-network.ts b/weaver/samples/fabric/fabric-cli/src/helpers/interop-setup/configure-network.ts index b85bbc1db6..3a33ad4ea5 100644 --- a/weaver/samples/fabric/fabric-cli/src/helpers/interop-setup/configure-network.ts +++ b/weaver/samples/fabric/fabric-cli/src/helpers/interop-setup/configure-network.ts @@ -142,13 +142,13 @@ const loadLocalHelper = async ( registerUser: false }) try { - const response = await MembershipManager.createLocalMembership(gateway, members, networkName, channelName, contractName) + const response = await MembershipManager.createLocalMembership(gateway, members, channelName, contractName) logger.info('CreateLocalMembership Successful.') } catch (e) { logger.error(e) logger.info('CreateLocalMembership attempting Update') - const response = await MembershipManager.updateLocalMembership(gateway, members, networkName, channelName, contractName) - logger.info('Update Local Memebrship response: success: ', response) + const response = await MembershipManager.updateLocalMembership(gateway, members, channelName, contractName) + logger.info('UpdateLocalMembership response: success: ', response) } } diff --git a/weaver/sdks/fabric/go-sdk/decoders/decoders.go b/weaver/sdks/fabric/go-sdk/decoders/decoders.go index 77a1edef3b..8eb7e9c1ed 100644 --- a/weaver/sdks/fabric/go-sdk/decoders/decoders.go +++ b/weaver/sdks/fabric/go-sdk/decoders/decoders.go @@ -13,8 +13,7 @@ import ( "fmt" "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric-protos-go/peer" - pb "github.com/hyperledger/fabric-protos-go/peer" + "github.com/hyperledger/fabric-protos-go-apiv2/peer" log "github.com/sirupsen/logrus" ) @@ -25,8 +24,8 @@ func logThenErrorf(format string, args ...interface{}) error { return errors.New(errorMsg) } -func DeserializeRemoteProposal(proposalBytes []byte) (*pb.Proposal, error) { - proposal := &pb.Proposal{} +func DeserializeRemoteProposal(proposalBytes []byte) (*peer.Proposal, error) { + proposal := &peer.Proposal{} err := proto.Unmarshal(proposalBytes, proposal) if err != nil { return proposal, logThenErrorf(err.Error()) @@ -35,8 +34,8 @@ func DeserializeRemoteProposal(proposalBytes []byte) (*pb.Proposal, error) { return proposal, nil } -func DeserializeRemoteProposalResponse(proposalResponseBytes []byte) (*pb.ProposalResponse, error) { - proposalResponse := &pb.ProposalResponse{} +func DeserializeRemoteProposalResponse(proposalResponseBytes []byte) (*peer.ProposalResponse, error) { + proposalResponse := &peer.ProposalResponse{} err := proto.Unmarshal(proposalResponseBytes, proposalResponse) if err != nil { return proposalResponse, logThenErrorf(err.Error()) @@ -45,7 +44,7 @@ func DeserializeRemoteProposalResponse(proposalResponseBytes []byte) (*pb.Propos return proposalResponse, nil } -func DeserializeRemoteProposalHex(proposalBytesHex []byte) (*pb.Proposal, error) { +func DeserializeRemoteProposalHex(proposalBytesHex []byte) (*peer.Proposal, error) { proposalBytes, err := hex.DecodeString(string(proposalBytesHex)) if err != nil { return nil, logThenErrorf("cannot decode 'hex' string (%s) to bytes error: %s", proposalBytesHex, err.Error()) @@ -54,7 +53,7 @@ func DeserializeRemoteProposalHex(proposalBytesHex []byte) (*pb.Proposal, error) return DeserializeRemoteProposal(proposalBytes) } -func DeserializeRemoteProposalResponseHex(proposalResponseBytesHex []byte) (*pb.ProposalResponse, error) { +func DeserializeRemoteProposalResponseHex(proposalResponseBytesHex []byte) (*peer.ProposalResponse, error) { proposalResponseBytes, err := hex.DecodeString(string(proposalResponseBytesHex)) if err != nil { return nil, logThenErrorf("cannot decode 'hex' string (%s) to bytes error: %s", proposalResponseBytesHex, err.Error()) @@ -63,13 +62,13 @@ func DeserializeRemoteProposalResponseHex(proposalResponseBytesHex []byte) (*pb. return DeserializeRemoteProposalResponse(proposalResponseBytes) } -func DeserializeRemoteProposalBase64(proposalBytesBase64 []byte) (*pb.Proposal, error) { +func DeserializeRemoteProposalBase64(proposalBytesBase64 []byte) (*peer.Proposal, error) { proposalBytes := base64.StdEncoding.EncodeToString(proposalBytesBase64) return DeserializeRemoteProposal([]byte(proposalBytes)) } -func DeserializeRemoteProposalResponseBase64(proposalResponseBytesBase64 []byte) (*pb.ProposalResponse, error) { +func DeserializeRemoteProposalResponseBase64(proposalResponseBytesBase64 []byte) (*peer.ProposalResponse, error) { proposalResponseBytes := base64.StdEncoding.EncodeToString(proposalResponseBytesBase64) return DeserializeRemoteProposalResponse([]byte(proposalResponseBytes)) diff --git a/weaver/sdks/fabric/go-sdk/go.mod b/weaver/sdks/fabric/go-sdk/go.mod index 86ec75c235..6e95fdf664 100644 --- a/weaver/sdks/fabric/go-sdk/go.mod +++ b/weaver/sdks/fabric/go-sdk/go.mod @@ -6,19 +6,23 @@ require ( github.com/golang/protobuf v1.5.3 github.com/google/uuid v1.3.0 github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.2 - github.com/hyperledger/fabric-protos-go v0.3.0 + github.com/hyperledger/fabric-admin-sdk v0.0.0 + github.com/hyperledger/fabric-gateway v1.2.1 + github.com/hyperledger/fabric-protos-go-apiv2 v0.3.1 github.com/sirupsen/logrus v1.8.1 - github.com/stretchr/testify v1.7.0 - google.golang.org/grpc v1.56.3 - google.golang.org/protobuf v1.30.0 + github.com/stretchr/testify v1.8.1 + google.golang.org/grpc v1.57.0 + google.golang.org/protobuf v1.31.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/hyperledger/fabric-protos-go v0.3.0 // indirect + github.com/miekg/pkcs11 v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - gopkg.in/yaml.v3 v3.0.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/weaver/sdks/fabric/go-sdk/go.sum b/weaver/sdks/fabric/go-sdk/go.sum index 612474eb93..82c677b7d5 100644 --- a/weaver/sdks/fabric/go-sdk/go.sum +++ b/weaver/sdks/fabric/go-sdk/go.sum @@ -1,25 +1,43 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.2 h1:RCScZbqnxdX1RDrp4HATGXs8Pbh2yLI6F6ULjAjTUso= github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.2/go.mod h1:3DmkYfZoc+TtcAgF3kX6CmQDNKKKCHgbaoQuYu/3ayc= +github.com/hyperledger/fabric-admin-sdk v0.0.0 h1:SS/qekuUUOzvx1+1UzJCEcHD/UcCDpTxqrCjOVoy1Rg= +github.com/hyperledger/fabric-admin-sdk v0.0.0/go.mod h1:AGAr/kVPWagaEh+bJeieTiajC4pbfcYXVySENqwk2Sc= +github.com/hyperledger/fabric-gateway v1.2.1 h1:K6b7Q+y0x47SQ2TVnLih2mFNQ7/izmdAhnFgiylfSVQ= +github.com/hyperledger/fabric-gateway v1.2.1/go.mod h1:SCuB+RNueO6nOiW7QAyfeh4PaB1d1U4R6WKuq0IG66I= github.com/hyperledger/fabric-protos-go v0.3.0 h1:MXxy44WTMENOh5TI8+PCK2x6pMj47Go2vFRKDHB2PZs= github.com/hyperledger/fabric-protos-go v0.3.0/go.mod h1:WWnyWP40P2roPmmvxsUXSvVI/CF6vwY1K1UFidnKBys= +github.com/hyperledger/fabric-protos-go-apiv2 v0.3.1 h1:zAxLu6XxaiOkNFl7iTO54RCc3fGO+5hjJKTqRfvxT1A= +github.com/hyperledger/fabric-protos-go-apiv2 v0.3.1/go.mod h1:2pq0ui6ZWA0cC8J+eCErgnMDCS1kPOEYVY+06ZAK0qE= +github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= +github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/onsi/ginkgo/v2 v2.8.2 h1:rWe/YULhcr//R7U3kN11ISrlT7aVPW9K/AbXbGakXqY= +github.com/onsi/gomega v1.27.0 h1:QLidEla4bXUuZVFa4KX6JHCsuGgbi85LC/pCHrt/O08= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -27,17 +45,18 @@ golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= -google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 h1:eSaPbMR4T7WfH9FvABk36NBMacoTUKdWCvV0dx+KfOg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/weaver/sdks/fabric/go-sdk/interoperablehelper/interoperable-helper.go b/weaver/sdks/fabric/go-sdk/interoperablehelper/interoperable-helper.go index 30041e69cd..20303947aa 100644 --- a/weaver/sdks/fabric/go-sdk/interoperablehelper/interoperable-helper.go +++ b/weaver/sdks/fabric/go-sdk/interoperablehelper/interoperable-helper.go @@ -16,7 +16,7 @@ import ( "github.com/google/uuid" "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric-protos-go/peer" + "github.com/hyperledger/fabric-protos-go-apiv2/peer" "github.com/hyperledger/cacti/weaver/common/protos-go/v2/common" "github.com/hyperledger/cacti/weaver/common/protos-go/v2/corda" "github.com/hyperledger/cacti/weaver/common/protos-go/v2/fabric" diff --git a/weaver/sdks/fabric/go-sdk/membershipmanager/membership_manager.go b/weaver/sdks/fabric/go-sdk/membershipmanager/membership_manager.go new file mode 100644 index 0000000000..654be316e5 --- /dev/null +++ b/weaver/sdks/fabric/go-sdk/membershipmanager/membership_manager.go @@ -0,0 +1,667 @@ +/* +Copyright 2020 IBM All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package membershipmanager + +import ( + "context" + "fmt" + "crypto" + "crypto/x509" + "encoding/base64" + "encoding/json" + "encoding/pem" + "net" + "os" + "strconv" + "strings" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + protoV2 "google.golang.org/protobuf/proto" + + "github.com/hyperledger/fabric-protos-go-apiv2/common" + mspprotos "github.com/hyperledger/fabric-protos-go-apiv2/msp" + "github.com/hyperledger/fabric-admin-sdk/pkg/channel" + "github.com/hyperledger/fabric-admin-sdk/pkg/identity" + "github.com/hyperledger/fabric-gateway/pkg/client" + cidentity "github.com/hyperledger/fabric-gateway/pkg/identity" + + cactiprotos "github.com/hyperledger/cacti/weaver/common/protos-go/v2/common" +) + + +func CreateLocalMembership(walletPath, userName, connectionProfilePath, channelId, weaverCCId string, mspIds []string) error { + membership, err := GetMSPConfigurations(walletPath, userName, connectionProfilePath, channelId, mspIds) + if err != nil { + return err + } + membership.SecurityDomain = "" // We don't need this as the Weaver chaincode will internally use a designated keyword + membershipBytes, err := protoV2.Marshal(membership) + if err != nil { + return err + } + membershipSerialized64 := base64.StdEncoding.EncodeToString(membershipBytes) + + _, err = membershipTx("CreateLocalMembership", walletPath, userName, connectionProfilePath, channelId, weaverCCId, membershipSerialized64, mspIds) + if err != nil { + return err + } + + return nil +} + +func UpdateLocalMembership(walletPath, userName, connectionProfilePath, channelId, weaverCCId string, mspIds []string) error { + membership, err := GetMSPConfigurations(walletPath, userName, connectionProfilePath, channelId, mspIds) + if err != nil { + return err + } + membership.SecurityDomain = "" // We don't need this as the Weaver chaincode will internally use a designated keyword + membershipBytes, err := protoV2.Marshal(membership) + if err != nil { + return err + } + membershipSerialized64 := base64.StdEncoding.EncodeToString(membershipBytes) + + _, err = membershipTx("UpdateLocalMembership", walletPath, userName, connectionProfilePath, channelId, weaverCCId, membershipSerialized64, mspIds) + if err != nil { + return err + } + + return nil +} + +func DeleteLocalMembership(walletPath, userName, connectionProfilePath, channelId, weaverCCId string, mspIds []string) error { + _, err := membershipTx("DeleteLocalMembership", walletPath, userName, connectionProfilePath, channelId, weaverCCId, "", mspIds) + if err != nil { + return err + } + + return nil +} + +func ReadMembership(walletPath, userName, connectionProfilePath, channelId, weaverCCId, securityDomain string, mspIds []string) (string, error) { + result, err := membershipTx("GetMembershipBySecurityDomain", walletPath, userName, connectionProfilePath, channelId, weaverCCId, securityDomain, mspIds) + if err != nil { + return "", err + } + + return string(result), nil +} + +func GetMembershipUnit(walletPath, userName, connectionProfilePath, channelId, mspId string) (*cactiprotos.Member, error) { + configBlock, err := GetConfigBlockFromChannel(walletPath, userName, connectionProfilePath, channelId) + if err != nil { + return nil, err + } + + return GetMembershipForMspIdFromBlock(configBlock, mspId) +} + +func GetMSPConfigurations(walletPath, userName, connectionProfilePath, channelId string, mspIds []string) (*cactiprotos.Membership, error) { + configBlock, err := GetConfigBlockFromChannel(walletPath, userName, connectionProfilePath, channelId) + if err != nil { + return nil, err + } + + return GetMembershipForMspIdsFromBlock(configBlock, mspIds) +} + +func GetAllMSPConfigurations(walletPath, userName, connectionProfilePath, channelId string, ordererMspIds []string) (*cactiprotos.Membership, error) { + configBlock, err := GetConfigBlockFromChannel(walletPath, userName, connectionProfilePath, channelId) + if err != nil { + return nil, err + } + + return GetMembershipForAllMspIdsFromBlock(configBlock, ordererMspIds) +} + +func GetConfigBlockFromChannel(walletPath, userName, connectionProfilePath, channelId string) (*common.Block, error) { + mspId, signCert, signKey, timeout, connection, err := getNetworkConnectionAndInfo(walletPath, userName, connectionProfilePath) + if err != nil { + return nil, err + } + defer connection.Close() + + // Client identity used to carry out deployment tasks. + signCertParsed, err := readCertificate(signCert) + if err != nil { + return nil, err + } + signKeyParsed, err := readPrivateKey(signKey) + if err != nil { + return nil, err + } + clientId, err := identity.NewPrivateKeySigningIdentity(mspId, signCertParsed, signKeyParsed) + if err != nil { + return nil, err + } + + // Context used to manage Fabric invocations. + seconds, err := time.ParseDuration(strconv.Itoa(timeout) + "s") + if err != nil { + return nil, err + } + ctx, cancel := context.WithTimeout(context.Background(), seconds*time.Second) + defer cancel() + + configBlock, err := channel.GetConfigBlock(ctx, connection, clientId, channelId) + if err != nil { + return nil, err + } + + return configBlock, err +} + +func GetMembershipForMspIdFromBlock(block *common.Block, mspId string) (*cactiprotos.Member, error) { + var envelope common.Envelope + err := protoV2.Unmarshal((block.GetData().GetData())[0], &envelope) + if err != nil { + return nil, err + } + + var payload common.Payload + err = protoV2.Unmarshal(envelope.GetPayload(), &payload) + if err != nil { + return nil, err + } + + var channelHeader common.ChannelHeader + err = protoV2.Unmarshal(payload.GetHeader().GetChannelHeader(), &channelHeader) + if err != nil { + return nil, err + } + + if common.HeaderType(channelHeader.GetType()) == common.HeaderType_CONFIG { + var configEnvelope common.ConfigEnvelope + err = protoV2.Unmarshal(payload.GetData(), &configEnvelope) + if err != nil { + return nil, err + } + + for _, group := range configEnvelope.GetConfig().GetChannelGroup().GetGroups()["Application"].GetGroups() { + var mspConfig mspprotos.MSPConfig + groupValMsp, ok := group.GetValues()["MSP"] + if !ok { + fmt.Println("Warning: Channel Application group has no 'MSP' key") + continue + } + err = protoV2.Unmarshal(groupValMsp.GetValue(), &mspConfig) + if err != nil { + return nil, err + } + + // Ideally, we would replace the '0' in the below conditional with 'int32(msp.FABRIC)' + // according to https://pkg.go.dev/github.com/hyperledger/fabric@v2.1.1+incompatible/msp#ProviderType + // but this would require importing "github.com/hyperledger/fabric/msp", + // which depends on 'fabric-protos-go', which in turn conflicts with 'fabric-protos-go-apiv2', + // which is imported by this module. + if mspConfig.GetType() == 0 { + var fabricMspConfig mspprotos.FabricMSPConfig + err = protoV2.Unmarshal(mspConfig.GetConfig(), &fabricMspConfig) + if err != nil { + return nil, err + } + + if fabricMspConfig.GetName() == mspId { + memberUnit := &cactiprotos.Member{} + memberUnit.Type = "certificate" + memberUnit.Value = "" + memberUnit.Chain = []string{} + for _, certBytes := range fabricMspConfig.GetRootCerts() { + memberUnit.Chain = append(memberUnit.Chain, string(certBytes)) + } + for _, certBytes := range fabricMspConfig.GetIntermediateCerts() { + memberUnit.Chain = append(memberUnit.Chain, string(certBytes)) + } + return memberUnit, nil + } + } + } + } + + return nil, nil +} + +func GetMembershipForMspIdsFromBlock(block *common.Block, mspIds []string) (*cactiprotos.Membership, error) { + // Convert slice to map + var mspMap = make(map[string]bool) + for _, mspId := range mspIds { + mspMap[mspId] = true + } + + var envelope common.Envelope + err := protoV2.Unmarshal((block.GetData().GetData())[0], &envelope) + if err != nil { + return nil, err + } + + var payload common.Payload + err = protoV2.Unmarshal(envelope.GetPayload(), &payload) + if err != nil { + return nil, err + } + + var channelHeader common.ChannelHeader + err = protoV2.Unmarshal(payload.GetHeader().GetChannelHeader(), &channelHeader) + if err != nil { + return nil, err + } + + membership := &cactiprotos.Membership{} + membership.Members = make(map[string]*cactiprotos.Member) + + if common.HeaderType(channelHeader.GetType()) == common.HeaderType_CONFIG { + var configEnvelope common.ConfigEnvelope + err = protoV2.Unmarshal(payload.GetData(), &configEnvelope) + if err != nil { + return nil, err + } + + for _, group := range configEnvelope.GetConfig().GetChannelGroup().GetGroups()["Application"].GetGroups() { + var mspConfig mspprotos.MSPConfig + groupValMsp, ok := group.GetValues()["MSP"] + if !ok { + fmt.Println("Warning: Channel Application group has no 'MSP' key") + continue + } + err = protoV2.Unmarshal(groupValMsp.GetValue(), &mspConfig) + if err != nil { + return nil, err + } + + // Ideally, we would replace the '0' in the below conditional with 'int32(msp.FABRIC)' + // according to https://pkg.go.dev/github.com/hyperledger/fabric@v2.1.1+incompatible/msp#ProviderType + // but this would require importing "github.com/hyperledger/fabric/msp", + // which depends on 'fabric-protos-go', which in turn conflicts with 'fabric-protos-go-apiv2', + // which is imported by this module. + if mspConfig.GetType() == 0 { + var fabricMspConfig mspprotos.FabricMSPConfig + err = protoV2.Unmarshal(mspConfig.GetConfig(), &fabricMspConfig) + if err != nil { + return nil, err + } + + if mspMap[fabricMspConfig.GetName()] == true { + memberUnit := &cactiprotos.Member{} + memberUnit.Type = "certificate" + memberUnit.Value = "" + memberUnit.Chain = []string{} + for _, certBytes := range fabricMspConfig.GetRootCerts() { + memberUnit.Chain = append(memberUnit.Chain, string(certBytes)) + } + for _, certBytes := range fabricMspConfig.GetIntermediateCerts() { + memberUnit.Chain = append(memberUnit.Chain, string(certBytes)) + } + membership.Members[fabricMspConfig.GetName()] = memberUnit + } + } + } + } + + return membership, nil +} + +func GetMembershipForAllMspIdsFromBlock(block *common.Block, ordererMspIds []string) (*cactiprotos.Membership, error) { + // Convert slice to map + var ordererMspMap = make(map[string]bool) + for _, mspId := range ordererMspIds { + ordererMspMap[mspId] = true + } + + var envelope common.Envelope + err := protoV2.Unmarshal((block.GetData().GetData())[0], &envelope) + if err != nil { + return nil, err + } + + var payload common.Payload + err = protoV2.Unmarshal(envelope.GetPayload(), &payload) + if err != nil { + return nil, err + } + + var channelHeader common.ChannelHeader + err = protoV2.Unmarshal(payload.GetHeader().GetChannelHeader(), &channelHeader) + if err != nil { + return nil, err + } + + membership := &cactiprotos.Membership{} + membership.Members = make(map[string]*cactiprotos.Member) + + if common.HeaderType(channelHeader.GetType()) == common.HeaderType_CONFIG { + var configEnvelope common.ConfigEnvelope + err = protoV2.Unmarshal(payload.GetData(), &configEnvelope) + if err != nil { + return nil, err + } + + for _, group := range configEnvelope.GetConfig().GetChannelGroup().GetGroups()["Application"].GetGroups() { + var mspConfig mspprotos.MSPConfig + groupValMsp, ok := group.GetValues()["MSP"] + if !ok { + fmt.Println("Warning: Channel Application group has no 'MSP' key") + continue + } + err = protoV2.Unmarshal(groupValMsp.GetValue(), &mspConfig) + if err != nil { + return nil, err + } + + // Ideally, we would replace the '0' in the below conditional with 'int32(msp.FABRIC)' + // according to https://pkg.go.dev/github.com/hyperledger/fabric@v2.1.1+incompatible/msp#ProviderType + // but this would require importing "github.com/hyperledger/fabric/msp", + // which depends on 'fabric-protos-go', which in turn conflicts with 'fabric-protos-go-apiv2', + // which is imported by this module. + if mspConfig.GetType() == 0 { + var fabricMspConfig mspprotos.FabricMSPConfig + err = protoV2.Unmarshal(mspConfig.GetConfig(), &fabricMspConfig) + if err != nil { + return nil, err + } + + if _, isOrdererMspId := ordererMspMap[fabricMspConfig.GetName()]; !isOrdererMspId { + memberUnit := &cactiprotos.Member{} + memberUnit.Type = "certificate" + memberUnit.Value = "" + memberUnit.Chain = []string{} + for _, certBytes := range fabricMspConfig.GetRootCerts() { + memberUnit.Chain = append(memberUnit.Chain, string(certBytes)) + } + for _, certBytes := range fabricMspConfig.GetIntermediateCerts() { + memberUnit.Chain = append(memberUnit.Chain, string(certBytes)) + } + membership.Members[fabricMspConfig.GetName()] = memberUnit + } + } + } + } + + return membership, nil +} + +func membershipTx(txFunc, walletPath, userName, connectionProfilePath, channelId, weaverCCId, ccArg string, mspIds []string) ([]byte, error) { + mspId, signCert, signKey, _, connection, err := getNetworkConnectionAndInfo(walletPath, userName, connectionProfilePath) + if err != nil { + return nil, err + } + defer connection.Close() + + id, err := newIdentity(signCert, mspId) + if err != nil { + return nil, err + } + + sign, err := newSign(signKey) + if err != nil { + return nil, err + } + + // Instantiate the network gateway + gateway, err := client.Connect(id, client.WithSign(sign), client.WithClientConnection(connection)) + if err != nil { + return nil, err + } + defer gateway.Close() + + network := gateway.GetNetwork(channelId) + weaverCC := network.GetContract(weaverCCId) + if ccArg == "" { + return weaverCC.SubmitTransaction(txFunc) + } else { + return weaverCC.SubmitTransaction(txFunc, ccArg) + } +} + +func getNetworkConnectionAndInfo(walletPath, userName, connectionProfilePath string) (string, string, string, int, *grpc.ClientConn, error) { + // gRPC connection to a target peer. + mspId, signCert, signKey, err := getInfoFromWallet(walletPath, userName) + if err != nil { + return "", "", "", -1, nil, err + } + peerEndpoint, tlsCaCert, timeout, err := getInfoFromConnectionProfile(connectionProfilePath, mspId) + if err != nil { + return "", "", "", -1, nil, err + } + connection, err := newGrpcConnection(peerEndpoint, tlsCaCert) + if err != nil { + return "", "", "", -1, nil, err + } + + return mspId, signCert, signKey, timeout, connection, nil +} + +// newIdentity creates a client identity for this Gateway connection using an X.509 certificate. +func newIdentity(certificatePEM, mspId string) (*cidentity.X509Identity, error) { + certificate, err := cidentity.CertificateFromPEM([]byte(certificatePEM)) + if err != nil { + return nil, err + } + + return cidentity.NewX509Identity(mspId, certificate) +} + +// newSign creates a function that generates a digital signature from a message digest using a private key. +func newSign(privateKeyPEM string) (cidentity.Sign, error) { + privateKey, err := cidentity.PrivateKeyFromPEM([]byte(privateKeyPEM)) + if err != nil { + return nil, err + } + + return cidentity.NewPrivateKeySign(privateKey) +} + +func getInfoFromWallet(walletPath, userName string) (string, string, string, error) { + walletUserId, err := os.ReadFile(walletPath + "/" + userName + ".id") + if err != nil { + return "", "", "", err + } + + var walletId = map[string]interface{}{} + err = json.Unmarshal(walletUserId, &walletId) + if err != nil { + return "", "", "", err + } + + walletCredentialsIface, ok := walletId["credentials"] + if !ok { + return "", "", "", fmt.Errorf("Wallet Id has no 'credentials' attribute") + } + var walletCredentials = walletCredentialsIface.(map[string]interface{}) + mspId, ok := walletId["mspId"] + if !ok { + return "", "", "", fmt.Errorf("Wallet Id has no 'mspId' attribute") + } + certificate, ok := walletCredentials["certificate"] + if !ok { + return "", "", "", fmt.Errorf("Wallet Id has no 'credentials.certificate' attribute") + } + privateKey, ok := walletCredentials["privateKey"] + if !ok { + return "", "", "", fmt.Errorf("Wallet Id has no 'credentials.privateKey' attribute") + } + + return mspId.(string), certificate.(string), privateKey.(string), nil +} + +func getInfoFromConnectionProfile(connectionProfilePath, mspId string) (string, string, int, error) { + connectionProfile, err := os.ReadFile(connectionProfilePath) + if err != nil { + return "", "", -1, err + } + + var connProfile = map[string]interface{}{} + err = json.Unmarshal(connectionProfile, &connProfile) + if err != nil { + return "", "", -1, err + } + + timeoutVal := 300 // peer connection timeout in seconds + // Get endorser timeout from the "client.connection.timeout.peer.endorser" attribute + clientIface, ok := connProfile["client"] + if !ok { + fmt.Println("Warning: Connection profile has no 'client' attribute") + } else { + var client = clientIface.(map[string]interface{}) + connectionIface, ok := client["connection"] + if !ok { + fmt.Println("Warning: Connection profile has no 'client.connection' attribute") + } else { + var connection = connectionIface.(map[string]interface{}) + timeoutIface, ok := connection["timeout"] + if !ok { + fmt.Println("Warning: Connection profile has no 'client.connection.timeout' attribute") + } else { + var timeout = timeoutIface.(map[string]interface{}) + tpeerIface, ok := timeout["peer"] + if !ok { + fmt.Println("Warning: Connection profile has no 'client.connection.timeout.peer' attribute") + } else { + var tpeer = tpeerIface.(map[string]interface{}) + endorserIface, ok := tpeer["endorser"] + if !ok { + fmt.Println("Warning: Connection profile has no 'client.connection.timeout.peer.endorser' attribute") + } else { + var endorser = endorserIface.(string) + profileTimeoutVal, err := strconv.Atoi(endorser) + if err != nil { + fmt.Printf("Warning: Cannot parse '%s'. Using default timeout` '%d'\n", endorser, timeoutVal) + } + timeoutVal = profileTimeoutVal + } + } + } + } + } + + orgsIface, ok := connProfile["organizations"] + if !ok { + return "", "", -1, fmt.Errorf("Connection profile has no 'organizations' attribute") + } + var orgs = orgsIface.(map[string]interface{}) + peersIface, ok := connProfile["peers"] + if !ok { + return "", "", -1, fmt.Errorf("Connection profile has no 'peers' attribute") + } + var peers = peersIface.(map[string]interface{}) + for orgName, orgInfo := range orgs { + var org = orgInfo.(map[string]interface{}) + orgMspId, ok := org["mspid"] + if !ok { + return "", "", -1, fmt.Errorf("Connection profile has no 'mspId' attribute for the '%s' organization", orgName) + } + if orgMspId == mspId { + orgPeers := org["peers"].([]interface{}) + if len(orgPeers) == 0 { + return "", "", -1, fmt.Errorf("No peers in connection profile for org with MSP ID %s", mspId) + } else { + peerId := orgPeers[0].(string) + peerInfo, ok := peers[peerId] + if !ok { + return "", "", -1, fmt.Errorf("Connection profile has no peer '%s' info", peerId) + } + var peer = peerInfo.(map[string]interface{}) + tlsCACertsIface, ok := peer["tlsCACerts"] + if !ok { + return "", "", -1, fmt.Errorf("Connection profile has no 'tlsCACerts' attribute for the '%s' peer", peerId) + } + var tlsCACerts = tlsCACertsIface.(map[string]interface{}) + peerUrlIface, ok := peer["url"] + if !ok { + return "", "", -1, fmt.Errorf("Connection profile has no 'url' attribute for the '%s' peer", peerId) + } + peerUrl := peerUrlIface.(string) + tlsCACertsPemIface, ok := tlsCACerts["pem"] + if !ok { + return "", "", -1, fmt.Errorf("Connection profile has no 'tlsCACerts.pem' attribute for the '%s' peer", peerId) + } + peerUrlParts := strings.Split(peerUrl, "://") + if len(peerUrlParts) == 1 { + return peerUrlParts[0], tlsCACertsPemIface.(string), timeoutVal, nil + } else { // If not 1, the slice must have a length larger than 1 + return peerUrlParts[1], tlsCACertsPemIface.(string), timeoutVal, nil + } + } + } + } + + return "", "", -1, fmt.Errorf("Unable to find required info in connection profile") +} + +func newGrpcConnection(networkPeerEndpoint, tlsCACertPEM string) (*grpc.ClientConn, error) { + tlsCACert, err := readCertificate(tlsCACertPEM) + if err != nil { + return nil, err + } + certPool := x509.NewCertPool() + certPool.AddCert(tlsCACert) + transportCredentials := credentials.NewClientTLSFromCert(certPool, "") + + networkPeerEndpointParts := strings.Split(networkPeerEndpoint, ":") + hostname := networkPeerEndpointParts[0] + port := networkPeerEndpointParts[1] + addresses, err := net.LookupHost(hostname) + + var connection *grpc.ClientConn + if err != nil || len(addresses) == 0 { + fmt.Printf("Warning: Cannot resolve supplied hostname '%s'. Using 'localhost' instead.\n", hostname) + connection, err = grpc.Dial("localhost:" + port, grpc.WithTransportCredentials(transportCredentials)) + } else { + connection, err = grpc.Dial(networkPeerEndpoint, grpc.WithTransportCredentials(transportCredentials)) + } + if err != nil { + return nil, err + } + + return connection, nil +} + +func readCertificateFile(certFile string) (*x509.Certificate, error) { + certificatePEM, err := os.ReadFile(certFile) + if err != nil { + return nil, err + } + + return readCertificate(string(certificatePEM)) +} + +func readCertificate(certificatePEM string) (*x509.Certificate, error) { + block, _ := pem.Decode([]byte(certificatePEM)) + if block == nil { + return nil, fmt.Errorf("failed to parse certificate PEM") + } + certificate, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, fmt.Errorf("failed to parse certificate: %s", err.Error()) + } + + return certificate, nil +} + +func readPrivateKeyFile(keyFile string) (crypto.PrivateKey, error) { + privateKeyPEM, err := os.ReadFile(keyFile) + if err != nil { + return nil, err + } + + return readPrivateKey(string(privateKeyPEM)) +} + +func readPrivateKey(privateKeyPEM string) (crypto.PrivateKey, error) { + block, _ := pem.Decode([]byte(privateKeyPEM)) + if block == nil { + return nil, fmt.Errorf("failed to parse private key PEM") + } + + privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("failed to parse PKCS8 encoded private key: %s", err.Error()) + } + + return privateKey, nil +} diff --git a/weaver/sdks/fabric/go-sdk/readme.md b/weaver/sdks/fabric/go-sdk/readme.md index 7bac8f4880..843cb54a69 100644 --- a/weaver/sdks/fabric/go-sdk/readme.md +++ b/weaver/sdks/fabric/go-sdk/readme.md @@ -21,6 +21,51 @@ Sample content for the values of these keys can be found in the file `helpers/te Also note that similar checks need to be carried out for the connection profile `yaml` file if you want to use the yaml file instead of json. Sample content for the values of these keys can be found in the file `helpers/testdata/example/peerOrganizations/org1.example.com/connection-tls.yaml`. +### Testing membership manager functions + +The [membership manager functions](./membershipmanager) are currently not covered by unit tests. As a temporary measure,below are instructions to test them in a standalone package as follows. +- Copy [membershipmanager/membership_manager.go](./membershipmanager/membership_manager.go) to an empty folder and rename the package to `main`. +- Add a `main` function with the following contents. These are samples, and you can tweak these as needed in your setup. + ```go + func main() { + walletPath := "" // e.g., /weaver/samples/fabric/fabric-cli/src/wallet-network1/ + userName := "networkadmin" // e.g., networkadmin + connectionProfilePath := "" // e.g., /weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.docker.json" + + fmt.Printf("Get Recorded local Membership: ") + member, _ := GetMembershipUnit(walletPath, userName, connectionProfilePath, "mychannel", "Org1MSP") + fmt.Printf("%+v\n", member) + + fmt.Printf("Get MSP Configuration for Org2MSP: ") + membership, _ := GetMSPConfigurations(walletPath, userName, connectionProfilePath, "mychannel", []string{"Org1MSP", "Org2MSP"}) + fmt.Printf("%+v\n", membership) + + fmt.Printf("Get All MSP Configuration for Org1MSP: ") + membership, _ = GetAllMSPConfigurations(walletPath, userName, connectionProfilePath, "mychannel", []string{"Org1MSP"}) + fmt.Printf("%+v\n", membership) + + fmt.Printf("Create Local Membership: ") + err := CreateLocalMembership(walletPath, userName, connectionProfilePath, "mychannel", "interop", []string{"Org1MSP"}) + fmt.Println(err) + + fmt.Printf("Update Local Membership: ") + err = UpdateLocalMembership(walletPath, userName, connectionProfilePath, "mychannel", "interop", []string{"Org1MSP"}) + fmt.Println(err) + + fmt.Printf("Read Local Membership: ") + m, err := ReadMembership(walletPath, userName, connectionProfilePath, "mychannel", "interop", "local-security-domain", []string{"Org1MSP"}) + fmt.Println(m) + fmt.Println(err) + + fmt.Printf("Delete Local Membership: ") + err = DeleteLocalMembership(walletPath, userName, connectionProfilePath, "mychannel", "interop", []string{"Org1MSP"}) + fmt.Println(err) + } + ``` +- Build the program. +- Start the Weaver testnet, e.g., by navigating to `/weaver/tests/network-setups/fabric/dev` and running `make start-interop-local`. +- Run the above program. You should see membership contents in the output with no errors. + ## Configurations - Set the output of the below command as the value of the key `"members"."Org1MSP"."value"` in the file `data/credentials/network1/membership.json` (similarly for `network2`). diff --git a/weaver/sdks/fabric/interoperation-node-sdk/src/MembershipManager.ts b/weaver/sdks/fabric/interoperation-node-sdk/src/MembershipManager.ts index c58038ad99..b0bf218d98 100644 --- a/weaver/sdks/fabric/interoperation-node-sdk/src/MembershipManager.ts +++ b/weaver/sdks/fabric/interoperation-node-sdk/src/MembershipManager.ts @@ -22,13 +22,12 @@ import { handlePromise, promisifyAll } from './helpers' async function createLocalMembership( gateway: Gateway, memberMspIds: Array, - securityDomain: string, channelName: string, weaverCCId: string ): Promise { const network = await gateway.getNetwork(channelName) const membership = getMSPConfigurations(network, memberMspIds) - membership.setSecuritydomain(securityDomain) + membership.setSecuritydomain('') const membership64 = Buffer.from(membership.serializeBinary()).toString('base64') const contract = network.getContract(weaverCCId) return await contract.submitTransaction("CreateLocalMembership", membership64); @@ -37,13 +36,12 @@ async function createLocalMembership( async function updateLocalMembership( gateway: Gateway, memberMspIds: Array, - securityDomain: string, channelName: string, weaverCCId: string ): Promise { const network = await gateway.getNetwork(channelName) const membership = getMSPConfigurations(network, memberMspIds) - membership.setSecuritydomain(securityDomain) + membership.setSecuritydomain('') const membership64 = Buffer.from(membership.serializeBinary()).toString('base64') const contract = network.getContract(weaverCCId) return await contract.submitTransaction("UpdateLocalMembership", membership64); @@ -51,16 +49,15 @@ async function updateLocalMembership( async function deleteLocalMembership( gateway: Gateway, - securityDomain: string, channelName: string, weaverCCId: string ): Promise { const network = await gateway.getNetwork(channelName) const contract = network.getContract(weaverCCId) - return await contract.submitTransaction("DeleteLocalMembership", securityDomain); + return await contract.submitTransaction("DeleteLocalMembership"); } -async function readLocalMembership( +async function readMembership( gateway: Gateway, securityDomain: string, channelName: string, @@ -68,7 +65,7 @@ async function readLocalMembership( ): Promise { const network = await gateway.getNetwork(channelName) const contract = network.getContract(weaverCCId) - return await contract.submitTransaction("DeleteLocalMembership", securityDomain); + return await contract.submitTransaction("GetMembershipBySecurityDomain", securityDomain); } function getMembershipUnit(channel: Channel, mspId: string): membership_pb.Member { @@ -204,6 +201,7 @@ export { createLocalMembership, updateLocalMembership, deleteLocalMembership, + readMembership, getMembershipUnit, getAllMSPConfigurations, syncMembershipFromIINAgent