Skip to content

Commit

Permalink
[FAB-7281] Resource Mgmt - Instantiate/Upgrade CC
Browse files Browse the repository at this point in the history
Change-Id: I9ae04f62d10dc61c4124a40f25a575cccc32dc5f
Signed-off-by: Sandra Vrtikapa <[email protected]>
  • Loading branch information
sandrask committed Dec 1, 2017
1 parent 015582c commit d3c36d4
Show file tree
Hide file tree
Showing 16 changed files with 1,228 additions and 554 deletions.
51 changes: 50 additions & 1 deletion api/apitxn/resmgmtclient/resmgmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ SPDX-License-Identifier: Apache-2.0

package resmgmt

import fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
import (
"time"

fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
common "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/common"
)

// TargetFilter allows for filtering target peers
type TargetFilter interface {
Expand Down Expand Up @@ -42,6 +47,38 @@ type InstallCCOpts struct {
TargetFilter TargetFilter // target filter
}

// InstantiateCCRequest contains instantiate chaincode request parameters
type InstantiateCCRequest struct {
Name string
Path string
Version string
Args [][]byte
Policy *common.SignaturePolicyEnvelope
}

// InstantiateCCOpts contains options for instantiating chaincode
type InstantiateCCOpts struct {
Targets []fab.Peer // target peers
TargetFilter TargetFilter // target filter
Timeout time.Duration
}

// UpgradeCCRequest contains upgrade chaincode request parameters
type UpgradeCCRequest struct {
Name string
Path string
Version string
Args [][]byte
Policy *common.SignaturePolicyEnvelope
}

// UpgradeCCOpts contains options for upgrading chaincode
type UpgradeCCOpts struct {
Targets []fab.Peer // target peers
TargetFilter TargetFilter // target filter
Timeout time.Duration
}

// ResourceMgmtClient is responsible for managing resources: peers joining channels, and installing and instantiating chaincodes(TODO).
type ResourceMgmtClient interface {

Expand All @@ -51,6 +88,18 @@ type ResourceMgmtClient interface {
// InstallCCWithOpts installs chaincode with custom options (specific peers, filtered peers)
InstallCCWithOpts(req InstallCCRequest, opts InstallCCOpts) ([]InstallCCResponse, error)

// InstantiateCC instantiates chaincode using default settings
InstantiateCC(channelID string, req InstantiateCCRequest) error

// InstantiateCCWithOpts instantiates chaincode with custom options (target peers, filtered peers)
InstantiateCCWithOpts(channelID string, req InstantiateCCRequest, opts InstantiateCCOpts) error

// UpgradeCC upgrades chaincode using default settings
UpgradeCC(channelID string, req UpgradeCCRequest) error

// UpgradeCCWithOpts upgrades chaincode with custom options (target peers, filtered peers)
UpgradeCCWithOpts(channelID string, req UpgradeCCRequest, opts UpgradeCCOpts) error

// JoinChannel allows for peers to join existing channel
JoinChannel(channelID string) error

Expand Down
21 changes: 4 additions & 17 deletions def/fabapi/context/defprovider/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ func (f *SessionClientFactory) NewResourceMgmtClient(sdk context.SDK, session co
return nil, err
}

discovery, err := sdk.DiscoveryProvider().NewDiscoveryService("")
provider := sdk.DiscoveryProvider()
if err != nil {
return nil, errors.WithMessage(err, "create discovery service failed")
return nil, errors.WithMessage(err, "create discovery provider failed")
}

return resmgmtImpl.NewResourceMgmtClient(client, discovery, filter, config)
return resmgmtImpl.NewResourceMgmtClient(client, provider, filter, config)
}

// NewChannelClient returns a client that can execute transactions on specified channel
Expand Down Expand Up @@ -146,16 +146,10 @@ func getEventHub(client fab.FabricClient, channelID string, session context.Sess
return nil, errors.WithMessage(err, "read configuration for channel peers failed")
}

serverHostOverride := ""
var eventSource *apiconfig.PeerConfig

for _, p := range peerConfig {

if p.EventSource && p.MspID == session.Identity().MspID() {
serverHostOverride = ""
if str, ok := p.GRPCOptions["ssl-target-name-override"].(string); ok {
serverHostOverride = str
}
eventSource = &p.PeerConfig
break
}
Expand All @@ -165,13 +159,6 @@ func getEventHub(client fab.FabricClient, channelID string, session context.Sess
return nil, errors.New("unable to find peer event source for channel")
}

// Event source found create event hub
eventHub, err := events.NewEventHub(client)
if err != nil {
return nil, err
}

eventHub.SetPeerAddr(eventSource.EventURL, eventSource.TLSCACerts.Path, serverHostOverride)
return events.NewEventHubFromConfig(client, eventSource)

return eventHub, nil
}
98 changes: 39 additions & 59 deletions pkg/fabric-client/channel/txnsender.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ func init() {
rand.Seed(time.Now().UnixNano())
}

// CCProposalType reflects transitions in the chaincode lifecycle
type CCProposalType int

// Define chaincode proposal types
const (
Instantiate CCProposalType = iota
Upgrade
)

// CreateTransaction create a transaction with proposal response, following the endorsement policy.
func (c *Channel) CreateTransaction(resps []*apitxn.TransactionProposalResponse) (*apitxn.Transaction, error) {
if len(resps) == 0 {
Expand Down Expand Up @@ -163,59 +172,8 @@ func (c *Channel) SendInstantiateProposal(chaincodeName string,
args [][]byte, chaincodePath string, chaincodeVersion string,
chaincodePolicy *common.SignaturePolicyEnvelope, targets []apitxn.ProposalProcessor) ([]*apitxn.TransactionProposalResponse, apitxn.TransactionID, error) {

if chaincodeName == "" {
return nil, apitxn.TransactionID{}, errors.New("chaincodeName is required")
}
if chaincodePath == "" {
return nil, apitxn.TransactionID{}, errors.New("chaincodePath is required")
}
if chaincodeVersion == "" {
return nil, apitxn.TransactionID{}, errors.New("chaincodeVersion is required")
}
if chaincodePolicy == nil {
return nil, apitxn.TransactionID{}, errors.New("chaincodePolicy is required")
}

// TODO: We should validate that targets are added to the channel.
if targets == nil || len(targets) < 1 {
return nil, apitxn.TransactionID{}, errors.New("missing peer objects for instantiate chaincode proposal")
}

ccds := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{
Type: pb.ChaincodeSpec_GOLANG, ChaincodeId: &pb.ChaincodeID{Name: chaincodeName, Path: chaincodePath, Version: chaincodeVersion},
Input: &pb.ChaincodeInput{Args: args}}}

if c.clientContext.UserContext() == nil {
return nil, apitxn.TransactionID{}, errors.New("user context is nil")
}
creator, err := c.clientContext.UserContext().Identity()
if err != nil {
return nil, apitxn.TransactionID{}, errors.Wrap(err, "getting user context's identity failed")
}
chaincodePolicyBytes, err := protos_utils.Marshal(chaincodePolicy)
if err != nil {
return nil, apitxn.TransactionID{}, err
}
// create a proposal from a chaincodeDeploymentSpec
proposal, txID, err := protos_utils.CreateDeployProposalFromCDS(c.Name(), ccds, creator, chaincodePolicyBytes, []byte("escc"), []byte("vscc"))
if err != nil {
return nil, apitxn.TransactionID{}, errors.Wrap(err, "create chaincode deploy proposal failed")
}

signedProposal, err := c.signProposal(proposal)
if err != nil {
return nil, apitxn.TransactionID{}, err
}

txnID := apitxn.TransactionID{ID: txID} // Nonce is missing

transactionProposalResponse, err := txnproc.SendTransactionProposalToProcessors(&apitxn.TransactionProposal{
SignedProposal: signedProposal,
Proposal: proposal,
TxnID: txnID,
}, targets)
return c.sendCCProposal(Instantiate, chaincodeName, args, chaincodePath, chaincodeVersion, chaincodePolicy, targets)

return transactionProposalResponse, txnID, err
}

// SendUpgradeProposal sends an upgrade proposal to one or more endorsing peers.
Expand All @@ -227,6 +185,15 @@ func (c *Channel) SendUpgradeProposal(chaincodeName string,
args [][]byte, chaincodePath string, chaincodeVersion string,
chaincodePolicy *common.SignaturePolicyEnvelope, targets []apitxn.ProposalProcessor) ([]*apitxn.TransactionProposalResponse, apitxn.TransactionID, error) {

return c.sendCCProposal(Upgrade, chaincodeName, args, chaincodePath, chaincodeVersion, chaincodePolicy, targets)

}

// helper function that sends an instantiate or upgrade chaincode proposal to one or more endorsing peers
func (c *Channel) sendCCProposal(ccProposalType CCProposalType, chaincodeName string,
args [][]byte, chaincodePath string, chaincodeVersion string,
chaincodePolicy *common.SignaturePolicyEnvelope, targets []apitxn.ProposalProcessor) ([]*apitxn.TransactionProposalResponse, apitxn.TransactionID, error) {

if chaincodeName == "" {
return nil, apitxn.TransactionID{}, errors.New("chaincodeName is required")
}
Expand All @@ -240,9 +207,8 @@ func (c *Channel) SendUpgradeProposal(chaincodeName string,
return nil, apitxn.TransactionID{}, errors.New("chaincodePolicy is required")
}

// TODO: We should validate that targets are added to the channel.
if targets == nil || len(targets) < 1 {
return nil, apitxn.TransactionID{}, errors.New("missing peer objects for upgrade chaincode proposal")
return nil, apitxn.TransactionID{}, errors.New("missing peer objects for chaincode proposal")
}

ccds := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{
Expand All @@ -260,10 +226,24 @@ func (c *Channel) SendUpgradeProposal(chaincodeName string,
if err != nil {
return nil, apitxn.TransactionID{}, err
}
// create a proposal from a chaincodeDeploymentSpec
proposal, txID, err := protos_utils.CreateUpgradeProposalFromCDS(c.Name(), ccds, creator, chaincodePolicyBytes, []byte("escc"), []byte("vscc"))
if err != nil {
return nil, apitxn.TransactionID{}, errors.Wrap(err, "create chaincode upgrade proposal failed")

var proposal *pb.Proposal
var txID string

switch ccProposalType {

case Instantiate:
proposal, txID, err = protos_utils.CreateDeployProposalFromCDS(c.Name(), ccds, creator, chaincodePolicyBytes, []byte("escc"), []byte("vscc"))
if err != nil {
return nil, apitxn.TransactionID{}, errors.Wrap(err, "create instantiate chaincode proposal failed")
}
case Upgrade:
proposal, txID, err = protos_utils.CreateUpgradeProposalFromCDS(c.Name(), ccds, creator, chaincodePolicyBytes, []byte("escc"), []byte("vscc"))
if err != nil {
return nil, apitxn.TransactionID{}, errors.Wrap(err, "create upgrade chaincode proposal failed")
}
default:
return nil, apitxn.TransactionID{}, errors.Errorf("chaincode proposal type %d not supported", ccProposalType)
}

signedProposal, err := c.signProposal(proposal)
Expand All @@ -282,7 +262,7 @@ func (c *Channel) SendUpgradeProposal(chaincodeName string,
return transactionProposalResponse, txnID, err
}

// SignPayload ... TODO.
// SignPayload signs payload
func (c *Channel) SignPayload(payload []byte) (*fab.SignedEnvelope, error) {
//Get user info
user := c.clientContext.UserContext()
Expand Down
5 changes: 3 additions & 2 deletions pkg/fabric-client/channel/txnsender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ func TestSendInstantiateProposal(t *testing.T) {

tresponse, txnid, err = channel.SendInstantiateProposal("qscc", nil, "test",
"1", cauthdsl.SignedByMspMember("Org1MSP"), nil)
if err == nil || err.Error() != "missing peer objects for instantiate chaincode proposal" {

if err == nil || err.Error() != "missing peer objects for chaincode proposal" {
t.Fatal("Missing peer objects validation is not working as expected")
}
}
Expand Down Expand Up @@ -259,7 +260,7 @@ func TestSendUpgradeProposal(t *testing.T) {

tresponse, txnid, err = channel.SendUpgradeProposal("qscc", nil, "test",
"2", cauthdsl.SignedByMspMember("Org1MSP"), nil)
if err == nil || err.Error() != "missing peer objects for upgrade chaincode proposal" {
if err == nil || err.Error() != "missing peer objects for chaincode proposal" {
t.Fatal("Missing peer objects validation is not working as expected")
}
}
Expand Down
20 changes: 20 additions & 0 deletions pkg/fabric-client/events/eventhub.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,26 @@ func NewEventHub(client fab.FabricClient) (*EventHub, error) {
return &eventHub, nil
}

// NewEventHubFromConfig creates new event hub from client and peer config
func NewEventHubFromConfig(client fab.FabricClient, peerCfg *apiconfig.PeerConfig) (*EventHub, error) {

eventHub, err := NewEventHub(client)
if err != nil {
return nil, err
}

serverHostOverride := ""
if str, ok := peerCfg.GRPCOptions["ssl-target-name-override"].(string); ok {
serverHostOverride = str
}

eventHub.peerAddr = peerCfg.EventURL
eventHub.peerTLSCertificate = peerCfg.TLSCACerts.Path
eventHub.peerTLSServerHostOverride = serverHostOverride

return eventHub, nil
}

// SetInterests clears all interests and sets the interests for BLOCK type of events.
func (eventHub *EventHub) SetInterests(block bool) {
eventHub.mtx.Lock()
Expand Down
2 changes: 1 addition & 1 deletion pkg/fabric-client/mocks/mockeventserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func StartMockEventServer(testAddress string) (*MockEventServer, error) {
}
eventServer := &MockEventServer{grpcServer: grpcServer}
pb.RegisterEventsServer(grpcServer, eventServer)
fmt.Printf("Starting test server\n")
fmt.Printf("Starting mock event server\n")
go grpcServer.Serve(lis)

return eventServer, nil
Expand Down
Loading

0 comments on commit d3c36d4

Please sign in to comment.