Skip to content

Commit

Permalink
[FAB-8542] Split invoke package from channel client
Browse files Browse the repository at this point in the history
This change moves transaction handlers from channel to
an invoke subpackage. The objective is to make the channel
package easier to understand.

Change-Id: I2b11152f78e2dd406f0826ffc427930285b4ba49
Signed-off-by: Troy Ronda <[email protected]>
  • Loading branch information
troyronda committed Feb 26, 2018
1 parent 5e51983 commit b8174ca
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 84 deletions.
49 changes: 12 additions & 37 deletions pkg/client/channel/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ package channel
import (
"time"

"github.com/hyperledger/fabric-sdk-go/pkg/context/api/core"
"github.com/hyperledger/fabric-sdk-go/pkg/context/api/fab"
"github.com/hyperledger/fabric-sdk-go/pkg/errors/retry"
pb "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/peer"
Expand All @@ -28,25 +27,25 @@ type CCEvent struct {
type Registration interface {
}

// Opts allows the user to specify more advanced options
type Opts struct {
// opts allows the user to specify more advanced options
type opts struct {
ProposalProcessors []fab.ProposalProcessor // targets
Timeout time.Duration
Retry retry.Opts
}

//Option func for each Opts argument
type Option func(opts *Opts) error
type Option func(opts *opts) error

// Request contains the parameters to execute transaction
// Request contains the parameters to query and execute an invocation transaction
type Request struct {
ChaincodeID string
Fcn string
Args [][]byte
TransientMap map[string][]byte
}

//Response contains response parameters for query and execute transaction
//Response contains response parameters for query and execute an invocation transaction
type Response struct {
Payload []byte
TransactionID fab.TransactionID
Expand All @@ -55,50 +54,26 @@ type Response struct {
Responses []*fab.TransactionProposalResponse
}

//Handler for chaining transaction executions
type Handler interface {
Handle(context *RequestContext, clientContext *ClientContext)
}

//ClientContext contains context parameters for handler execution
type ClientContext struct {
CryptoSuite core.CryptoSuite
Discovery fab.DiscoveryService
Selection fab.SelectionService
Channel fab.Channel // TODO: this should be removed when we have MSP split out.
Transactor fab.Transactor
EventHub fab.EventHub
}

//RequestContext contains request, opts, response parameters for handler execution
type RequestContext struct {
Request Request
Opts Opts
Response Response
Error error
RetryHandler retry.Handler
}

//WithTimeout encapsulates time.Duration to Option
func WithTimeout(timeout time.Duration) Option {
return func(opts *Opts) error {
opts.Timeout = timeout
return func(o *opts) error {
o.Timeout = timeout
return nil
}
}

//WithProposalProcessor encapsulates ProposalProcessors to Option
func WithProposalProcessor(proposalProcessors ...fab.ProposalProcessor) Option {
return func(opts *Opts) error {
opts.ProposalProcessors = proposalProcessors
return func(o *opts) error {
o.ProposalProcessors = proposalProcessors
return nil
}
}

// WithRetry option to configure retries
func WithRetry(opt retry.Opts) Option {
return func(opts *Opts) error {
opts.Retry = opt
func WithRetry(retryOpt retry.Opts) Option {
return func(o *opts) error {
o.Retry = retryOpt
return nil
}
}
35 changes: 18 additions & 17 deletions pkg/client/channel/chclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/hyperledger/fabric-sdk-go/pkg/context/api/core"

"github.com/hyperledger/fabric-sdk-go/pkg/client/channel/invoke"
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/discovery"
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/discovery/greylist"
"github.com/hyperledger/fabric-sdk-go/pkg/context"
Expand Down Expand Up @@ -88,16 +89,16 @@ func New(c Context) (*Client, error) {

// Query chaincode using request and optional options provided
func (cc *Client) Query(request Request, options ...Option) (Response, error) {
return cc.InvokeHandler(NewQueryHandler(), request, cc.addDefaultTimeout(core.Query, options...)...)
return cc.InvokeHandler(invoke.NewQueryHandler(), request, cc.addDefaultTimeout(core.Query, options...)...)
}

// Execute prepares and executes transaction using request and optional options provided
func (cc *Client) Execute(request Request, options ...Option) (Response, error) {
return cc.InvokeHandler(NewExecuteHandler(), request, cc.addDefaultTimeout(core.Execute, options...)...)
return cc.InvokeHandler(invoke.NewExecuteHandler(), request, cc.addDefaultTimeout(core.Execute, options...)...)
}

//InvokeHandler invokes handler using request and options provided
func (cc *Client) InvokeHandler(handler Handler, request Request, options ...Option) (Response, error) {
func (cc *Client) InvokeHandler(handler invoke.Handler, request Request, options ...Option) (Response, error) {
//Read execute tx options
txnOpts, err := cc.prepareOptsFromOptions(options...)
if err != nil {
Expand All @@ -123,14 +124,14 @@ func (cc *Client) InvokeHandler(handler Handler, request Request, options ...Opt
}()
select {
case <-complete:
return requestContext.Response, requestContext.Error
return Response(requestContext.Response), requestContext.Error
case <-time.After(requestContext.Opts.Timeout):
return Response{}, status.New(status.ClientStatus, status.Timeout.ToInt32(),
"request timed out", nil)
}
}

func (cc *Client) resolveRetry(ctx *RequestContext, opts Opts) bool {
func (cc *Client) resolveRetry(ctx *invoke.RequestContext, o opts) bool {
errs, ok := ctx.Error.(multi.Errors)
if !ok {
errs = append(errs, ctx.Error)
Expand All @@ -141,9 +142,9 @@ func (cc *Client) resolveRetry(ctx *RequestContext, opts Opts) bool {
cc.greylist.Greylist(e)

// Reset context parameters
ctx.Opts.ProposalProcessors = opts.ProposalProcessors
ctx.Opts.ProposalProcessors = o.ProposalProcessors
ctx.Error = nil
ctx.Response = Response{}
ctx.Response = invoke.Response{}

return true
}
Expand All @@ -152,25 +153,25 @@ func (cc *Client) resolveRetry(ctx *RequestContext, opts Opts) bool {
}

//prepareHandlerContexts prepares context objects for handlers
func (cc *Client) prepareHandlerContexts(request Request, options Opts) (*RequestContext, *ClientContext, error) {
func (cc *Client) prepareHandlerContexts(request Request, o opts) (*invoke.RequestContext, *invoke.ClientContext, error) {

if request.ChaincodeID == "" || request.Fcn == "" {
return nil, nil, errors.New("ChaincodeID and Fcn are required")
}

clientContext := &ClientContext{
clientContext := &invoke.ClientContext{
Selection: cc.selection,
Discovery: cc.discovery,
Channel: cc.channel,
Transactor: cc.transactor,
EventHub: cc.eventHub,
}

requestContext := &RequestContext{
Request: request,
Opts: options,
Response: Response{},
RetryHandler: retry.New(options.Retry),
requestContext := &invoke.RequestContext{
Request: invoke.Request(request),
Opts: invoke.Opts(o),
Response: invoke.Response{},
RetryHandler: retry.New(o.Retry),
}

if requestContext.Opts.Timeout == 0 {
Expand All @@ -181,8 +182,8 @@ func (cc *Client) prepareHandlerContexts(request Request, options Opts) (*Reques
}

//prepareOptsFromOptions Reads apitxn.Opts from Option array
func (cc *Client) prepareOptsFromOptions(options ...Option) (Opts, error) {
txnOpts := Opts{}
func (cc *Client) prepareOptsFromOptions(options ...Option) (opts, error) {
txnOpts := opts{}
for _, option := range options {
err := option(&txnOpts)
if err != nil {
Expand All @@ -194,7 +195,7 @@ func (cc *Client) prepareOptsFromOptions(options ...Option) (Opts, error) {

//addDefaultTimeout adds given default timeout if it is missing in options
func (cc *Client) addDefaultTimeout(timeOutType core.TimeoutType, options ...Option) []Option {
txnOpts := Opts{}
txnOpts := opts{}
for _, option := range options {
option(&txnOpts)
}
Expand Down
21 changes: 11 additions & 10 deletions pkg/client/channel/chclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,23 @@ import (
"testing"
"time"

"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/msp"
"github.com/hyperledger/fabric-sdk-go/pkg/context/api/core"
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/common"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"

"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/msp"
"github.com/hyperledger/fabric-sdk-go/pkg/client/channel/invoke"
txnmocks "github.com/hyperledger/fabric-sdk-go/pkg/client/common/mocks"
"github.com/hyperledger/fabric-sdk-go/pkg/context"
"github.com/hyperledger/fabric-sdk-go/pkg/context/api/core"
"github.com/hyperledger/fabric-sdk-go/pkg/context/api/fab"
"github.com/hyperledger/fabric-sdk-go/pkg/errors/retry"
"github.com/hyperledger/fabric-sdk-go/pkg/errors/status"
"github.com/hyperledger/fabric-sdk-go/pkg/fab/channel"
fcmocks "github.com/hyperledger/fabric-sdk-go/pkg/fab/mocks"
"github.com/hyperledger/fabric-sdk-go/pkg/fab/peer"
"github.com/hyperledger/fabric-sdk-go/pkg/fab/txn"
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/peer"
"github.com/pkg/errors"
)

const (
Expand Down Expand Up @@ -225,7 +226,7 @@ type customHandler struct {
expectedPayload []byte
}

func (c *customHandler) Handle(requestContext *RequestContext, clientContext *ClientContext) {
func (c *customHandler) Handle(requestContext *invoke.RequestContext, clientContext *invoke.ClientContext) {
requestContext.Response.Payload = c.expectedPayload
}

Expand All @@ -248,10 +249,10 @@ func TestInvokeHandler(t *testing.T) {
// and instead sends the proposal to the given channel
type customEndorsementHandler struct {
transactor fab.Transactor
next Handler
next invoke.Handler
}

func (h *customEndorsementHandler) Handle(requestContext *RequestContext, clientContext *ClientContext) {
func (h *customEndorsementHandler) Handle(requestContext *invoke.RequestContext, clientContext *invoke.ClientContext) {
transactionProposalResponses, txnID, err := createAndSendTestTransactionProposal(h.transactor, &requestContext.Request, requestContext.Opts.ProposalProcessors)

requestContext.Response.TransactionID = txnID
Expand Down Expand Up @@ -285,10 +286,10 @@ func TestQueryWithCustomEndorser(t *testing.T) {
}

response, err := chClient.InvokeHandler(
NewProposalProcessorHandler(
invoke.NewProposalProcessorHandler(
&customEndorsementHandler{
transactor: &transactor,
next: NewEndorsementValidationHandler(),
next: invoke.NewEndorsementValidationHandler(),
},
),
Request{ChaincodeID: "testCC", Fcn: "invoke", Args: [][]byte{[]byte("query"), []byte("b")}},
Expand Down Expand Up @@ -634,7 +635,7 @@ func setupChannelClientWithNodes(peers []fab.Peer,
return ch
}

func createAndSendTestTransactionProposal(sender fab.ProposalSender, chrequest *Request, targets []fab.ProposalProcessor) ([]*fab.TransactionProposalResponse, fab.TransactionID, error) {
func createAndSendTestTransactionProposal(sender fab.ProposalSender, chrequest *invoke.Request, targets []fab.ProposalProcessor) ([]*fab.TransactionProposalResponse, fab.TransactionID, error) {
request := fab.ChaincodeInvokeRequest{
ChaincodeID: chrequest.ChaincodeID,
Fcn: chrequest.Fcn,
Expand Down
65 changes: 65 additions & 0 deletions pkg/client/channel/invoke/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

// Package invoke provides the handlers for performing chaincode invocations.
package invoke

import (
"time"

"github.com/hyperledger/fabric-sdk-go/pkg/context/api/core"
"github.com/hyperledger/fabric-sdk-go/pkg/context/api/fab"
"github.com/hyperledger/fabric-sdk-go/pkg/errors/retry"
pb "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/peer"
)

// Opts allows the user to specify more advanced options
type Opts struct {
ProposalProcessors []fab.ProposalProcessor // targets
Timeout time.Duration
Retry retry.Opts
}

// Request contains the parameters to execute transaction
type Request struct {
ChaincodeID string
Fcn string
Args [][]byte
TransientMap map[string][]byte
}

//Response contains response parameters for query and execute transaction
type Response struct {
Payload []byte
TransactionID fab.TransactionID
TxValidationCode pb.TxValidationCode
Proposal *fab.TransactionProposal
Responses []*fab.TransactionProposalResponse
}

//Handler for chaining transaction executions
type Handler interface {
Handle(context *RequestContext, clientContext *ClientContext)
}

//ClientContext contains context parameters for handler execution
type ClientContext struct {
CryptoSuite core.CryptoSuite
Discovery fab.DiscoveryService
Selection fab.SelectionService
Channel fab.Channel // TODO: this should be removed when we have MSP split out.
Transactor fab.Transactor
EventHub fab.EventHub
}

//RequestContext contains request, opts, response parameters for handler execution
type RequestContext struct {
Request Request
Opts Opts
Response Response
Error error
RetryHandler retry.Handler
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package channel
package invoke

import (
"github.com/hyperledger/fabric-sdk-go/pkg/errors/status"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package channel
package invoke

import (
"errors"
"strings"
"testing"

"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/msp"
"github.com/stretchr/testify/assert"

"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/msp"
txnmocks "github.com/hyperledger/fabric-sdk-go/pkg/client/common/mocks"
"github.com/hyperledger/fabric-sdk-go/pkg/context/api/fab"
fcmocks "github.com/hyperledger/fabric-sdk-go/pkg/fab/mocks"
"github.com/stretchr/testify/assert"
)

func TestSignatureValidationHandlerSuccess(t *testing.T) {
Expand Down
Loading

0 comments on commit b8174ca

Please sign in to comment.