Skip to content

Commit

Permalink
[FAB-9023] return TransactionID for transactions
Browse files Browse the repository at this point in the history
for SaveChannel, InstantiateCC, UpgradeCC
When a transaction is stored to the ledger,
the SDK should return the ID of the transaction.
Additionally, fixed bug when (nil, nil) was returned
instead of an error in createChaincodeDeployProposal.

Change-Id: I3987de56fcd0e9c52948554b5857d9cd79212814
Signed-off-by: Dennis Kuhnert <[email protected]>
  • Loading branch information
Dennis Kuhnert committed Mar 21, 2018
1 parent ccecff4 commit 9880e07
Show file tree
Hide file tree
Showing 16 changed files with 179 additions and 187 deletions.
3 changes: 1 addition & 2 deletions pkg/client/resmgmt/lscc.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,13 @@ func createChaincodeDeployProposal(txh fab.TransactionHeader, deploy chaincodePr
case UpgradeChaincode:
fcn = lsccUpgrade
default:
return nil, errors.WithMessage(err, "chaincode deployment type unknown")
return nil, errors.New("chaincode deployment type unknown")
}

cir := fab.ChaincodeInvokeRequest{
ChaincodeID: lscc,
Fcn: fcn,
Args: args,
}

return txn.CreateChaincodeInvokeProposal(txh, cir)
}
93 changes: 53 additions & 40 deletions pkg/client/resmgmt/resmgmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ type InstantiateCCRequest struct {
CollConfig []*common.CollectionConfig
}

// InstantiateCCResponse contains response parameters for Instantiate
type InstantiateCCResponse struct {
TransactionID fab.TransactionID
}

// UpgradeCCRequest contains upgrade chaincode request parameters
type UpgradeCCRequest struct {
Name string
Expand All @@ -71,6 +76,11 @@ type UpgradeCCRequest struct {
CollConfig []*common.CollectionConfig
}

// UpgradeCCResponse contains response parameters for Upgrade
type UpgradeCCResponse struct {
TransactionID fab.TransactionID
}

//requestOptions contains options for operations performed by ResourceMgmtClient
type requestOptions struct {
Targets []fab.Peer // target peers
Expand Down Expand Up @@ -399,31 +409,33 @@ func checkRequiredInstallCCParams(req InstallCCRequest) error {
}

// InstantiateCC instantiates chaincode using default settings
func (rc *Client) InstantiateCC(channelID string, req InstantiateCCRequest, options ...RequestOption) error {
func (rc *Client) InstantiateCC(channelID string, req InstantiateCCRequest, options ...RequestOption) (InstantiateCCResponse, error) {

opts, err := rc.prepareRequestOpts(options...)
if err != nil {
return errors.WithMessage(err, "failed to get opts for InstantiateCC")
return InstantiateCCResponse{}, errors.WithMessage(err, "failed to get opts for InstantiateCC")
}

reqCtx, cancel := rc.createRequestContext(opts, core.ResMgmt)
defer cancel()

return rc.sendCCProposal(reqCtx, InstantiateChaincode, channelID, req, opts)
txID, err := rc.sendCCProposal(reqCtx, InstantiateChaincode, channelID, req, opts)
return InstantiateCCResponse{TransactionID: txID}, err
}

// UpgradeCC upgrades chaincode with optional custom options (specific peers, filtered peers, timeout)
func (rc *Client) UpgradeCC(channelID string, req UpgradeCCRequest, options ...RequestOption) error {
func (rc *Client) UpgradeCC(channelID string, req UpgradeCCRequest, options ...RequestOption) (UpgradeCCResponse, error) {

opts, err := rc.prepareRequestOpts(options...)
if err != nil {
return errors.WithMessage(err, "failed to get opts for UpgradeCC")
return UpgradeCCResponse{}, errors.WithMessage(err, "failed to get opts for UpgradeCC")
}

reqCtx, cancel := rc.createRequestContext(opts, core.ResMgmt)
defer cancel()

return rc.sendCCProposal(reqCtx, UpgradeChaincode, channelID, InstantiateCCRequest(req), opts)
txID, err := rc.sendCCProposal(reqCtx, UpgradeChaincode, channelID, InstantiateCCRequest(req), opts)
return UpgradeCCResponse{TransactionID: txID}, err
}

// QueryInstalledChaincodes queries the installed chaincodes on a peer.
Expand Down Expand Up @@ -522,91 +534,92 @@ func (rc *Client) QueryChannels(options ...RequestOption) (*pb.ChannelQueryRespo
}

// sendCCProposal sends proposal for type Instantiate, Upgrade
func (rc *Client) sendCCProposal(reqCtx reqContext.Context, ccProposalType chaincodeProposalType, channelID string, req InstantiateCCRequest, opts requestOptions) error {
func (rc *Client) sendCCProposal(reqCtx reqContext.Context, ccProposalType chaincodeProposalType, channelID string, req InstantiateCCRequest, opts requestOptions) (fab.TransactionID, error) {

if err := checkRequiredCCProposalParams(channelID, req); err != nil {
return err
return fab.EmptyTransactionID, err
}

// per channel discovery service
discovery, err := rc.ctx.DiscoveryProvider().CreateDiscoveryService(channelID)
if err != nil {
return errors.WithMessage(err, "failed to create channel discovery service")
return fab.EmptyTransactionID, errors.WithMessage(err, "failed to create channel discovery service")
}

//Default targets when targets are not provided in options
if len(opts.Targets) == 0 {
opts.Targets, err = rc.getDefaultTargets(discovery)
if err != nil {
return errors.WithMessage(err, "failed to get default targets for cc proposal")
return fab.EmptyTransactionID, errors.WithMessage(err, "failed to get default targets for cc proposal")
}
}

targets, err := rc.calculateTargets(discovery, opts.Targets, opts.TargetFilter)
if err != nil {
return errors.WithMessage(err, "failed to determine target peers for cc proposal")
return fab.EmptyTransactionID, errors.WithMessage(err, "failed to determine target peers for cc proposal")
}

if len(targets) == 0 {
return errors.WithStack(status.New(status.ClientStatus, status.NoPeersFound.ToInt32(), "no targets available", nil))
return fab.EmptyTransactionID, errors.WithStack(status.New(status.ClientStatus, status.NoPeersFound.ToInt32(), "no targets available", nil))
}

// Get transactor on the channel to create and send the deploy proposal
channelService, err := rc.ctx.ChannelProvider().ChannelService(rc.ctx, channelID)
if err != nil {
return errors.WithMessage(err, "Unable to get channel service")
return fab.EmptyTransactionID, errors.WithMessage(err, "Unable to get channel service")
}

chConfig, err := channelService.ChannelConfig()
if err != nil {
return errors.WithMessage(err, "get channel config failed")
return fab.EmptyTransactionID, errors.WithMessage(err, "get channel config failed")
}
transactor, err := rc.ctx.InfraProvider().CreateChannelTransactor(reqCtx, chConfig)
if err != nil {
return errors.WithMessage(err, "get channel transactor failed")
return fab.EmptyTransactionID, errors.WithMessage(err, "get channel transactor failed")
}

// create a transaction proposal for chaincode deployment
deployProposal := chaincodeDeployRequest(req)

txid, err := txn.NewHeader(rc.ctx, channelID)
txID, err := txn.NewHeader(rc.ctx, channelID)
if err != nil {
return errors.WithMessage(err, "create transaction ID failed")
return fab.EmptyTransactionID, errors.WithMessage(err, "create transaction ID failed")
}
tp, err := createChaincodeDeployProposal(txid, ccProposalType, channelID, deployProposal)

tp, err := createChaincodeDeployProposal(txID, ccProposalType, channelID, deployProposal)
if err != nil {
return errors.WithMessage(err, "creating chaincode deploy transaction proposal failed")
return txID.TransactionID(), errors.WithMessage(err, "creating chaincode deploy transaction proposal failed")
}

// Process and send transaction proposal
txProposalResponse, err := transactor.SendTransactionProposal(tp, peersToTxnProcessors(targets))
if err != nil {
return errors.WithMessage(err, "sending deploy transaction proposal failed")
return tp.TxnID, errors.WithMessage(err, "sending deploy transaction proposal failed")
}

// Membership is required to verify signature
membership, err := channelService.Membership()
if err != nil {
return errors.WithMessage(err, "membership creation failed")
return tp.TxnID, errors.WithMessage(err, "membership creation failed")
}

// Verify signature(s)
sv := &verifier.Signature{Membership: membership}
for _, r := range txProposalResponse {
if err := sv.Verify(r); err != nil {
return errors.WithMessage(err, "Failed to verify signature")
return tp.TxnID, errors.WithMessage(err, "Failed to verify signature")
}
}

eventService, err := channelService.EventService()
if err != nil {
return errors.WithMessage(err, "unable to get event service")
return tp.TxnID, errors.WithMessage(err, "unable to get event service")
}

// Register for commit event
reg, statusNotifier, err := eventService.RegisterTxStatusEvent(string(tp.TxnID))
if err != nil {
return errors.WithMessage(err, "error registering for TxStatus event")
return tp.TxnID, errors.WithMessage(err, "error registering for TxStatus event")
}
defer eventService.Unregister(reg)

Expand All @@ -615,17 +628,17 @@ func (rc *Client) sendCCProposal(reqCtx reqContext.Context, ccProposalType chain
ProposalResponses: txProposalResponse,
}
if _, err = createAndSendTransaction(transactor, transactionRequest); err != nil {
return errors.WithMessage(err, "CreateAndSendTransaction failed")
return tp.TxnID, errors.WithMessage(err, "CreateAndSendTransaction failed")
}

select {
case txStatus := <-statusNotifier:
if txStatus.TxValidationCode == pb.TxValidationCode_VALID {
return nil
return fab.TransactionID(txStatus.TxID), nil
}
return status.New(status.EventServerStatus, int32(txStatus.TxValidationCode), "instantiateOrUpgradeCC failed", nil)
return fab.TransactionID(txStatus.TxID), status.New(status.EventServerStatus, int32(txStatus.TxValidationCode), "instantiateOrUpgradeCC failed", nil)
case <-reqCtx.Done():
return errors.New("instantiateOrUpgradeCC timed out or cancelled")
return tp.TxnID, errors.New("instantiateOrUpgradeCC timed out or cancelled")
}

}
Expand Down Expand Up @@ -669,24 +682,24 @@ func peersToTxnProcessors(peers []fab.Peer) []fab.ProposalProcessor {
}

// SaveChannel creates or updates channel
func (rc *Client) SaveChannel(req SaveChannelRequest, options ...RequestOption) error {
func (rc *Client) SaveChannel(req SaveChannelRequest, options ...RequestOption) (fab.TransactionID, error) {

opts, err := rc.prepareRequestOpts(options...)
if err != nil {
return err
return fab.EmptyTransactionID, err
}

if req.ChannelConfigPath != "" {
configReader, err := os.Open(req.ChannelConfigPath)
if err != nil {
return errors.Wrapf(err, "opening channel config file failed")
return fab.EmptyTransactionID, errors.Wrapf(err, "opening channel config file failed")
}
defer loggedClose(configReader)
req.ChannelConfig = configReader
}

if req.ChannelID == "" || req.ChannelConfig == nil {
return errors.New("must provide channel ID and channel config")
return fab.EmptyTransactionID, errors.New("must provide channel ID and channel config")
}

logger.Debugf("saving channel: %s", req.ChannelID)
Expand All @@ -704,17 +717,17 @@ func (rc *Client) SaveChannel(req SaveChannelRequest, options ...RequestOption)
} else if rc.ctx != nil {
signers = append(signers, rc.ctx)
} else {
return errors.New("must provide signing user")
return fab.EmptyTransactionID, errors.New("must provide signing user")
}

configTx, err := ioutil.ReadAll(req.ChannelConfig)
if err != nil {
return errors.WithMessage(err, "reading channel config file failed")
return fab.EmptyTransactionID, errors.WithMessage(err, "reading channel config file failed")
}

chConfig, err := resource.ExtractChannelConfig(configTx)
if err != nil {
return errors.WithMessage(err, "extracting channel config failed")
return fab.EmptyTransactionID, errors.WithMessage(err, "extracting channel config failed")
}

var configSignatures []*common.ConfigSignature
Expand All @@ -727,14 +740,14 @@ func (rc *Client) SaveChannel(req SaveChannelRequest, options ...RequestOption)

configSignature, err := resource.CreateConfigSignature(&sigCtx, chConfig)
if err != nil {
return errors.WithMessage(err, "signing configuration failed")
return fab.EmptyTransactionID, errors.WithMessage(err, "signing configuration failed")
}
configSignatures = append(configSignatures, configSignature)
}

orderer, err := rc.requestOrderer(&opts, req.ChannelID)
if err != nil {
return errors.WithMessage(err, "failed to find orderer for request")
return fab.EmptyTransactionID, errors.WithMessage(err, "failed to find orderer for request")
}

request := api.CreateChannelRequest{
Expand All @@ -747,12 +760,12 @@ func (rc *Client) SaveChannel(req SaveChannelRequest, options ...RequestOption)
reqCtx, cancel := rc.createRequestContext(opts, core.OrdererResponse)
defer cancel()

_, err = resource.CreateChannel(reqCtx, request)
txID, err := resource.CreateChannel(reqCtx, request)
if err != nil {
return errors.WithMessage(err, "create channel failed")
return fab.EmptyTransactionID, errors.WithMessage(err, "create channel failed")
}

return nil
return txID, nil
}

func loggedClose(c io.Closer) {
Expand Down
Loading

0 comments on commit 9880e07

Please sign in to comment.