Skip to content

Commit

Permalink
[FAB-6382] - Add TxValidationCode to ExecuteTxResponse
Browse files Browse the repository at this point in the history
Added TxValidationCode to ExecuteTxResponse so that the
client knows the reason that the transaction failed.

Change-Id: I5873e282dc447cd043273d294099dbe54e118872
Signed-off-by: Bob Stasyszyn <[email protected]>
  • Loading branch information
bstasyszyn committed Oct 2, 2017
1 parent e89a861 commit 2578687
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 39 deletions.
11 changes: 8 additions & 3 deletions api/apitxn/txn.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ SPDX-License-Identifier: Apache-2.0

package apitxn

import "time"
import (
"time"

pb "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/peer"
)

// QueryRequest contains the parameters for query
type QueryRequest struct {
Expand All @@ -30,8 +34,9 @@ type QueryResponse struct {

// ExecuteTxResponse contains result of asynchronous call
type ExecuteTxResponse struct {
Response TransactionID
Error error
Response TransactionID
Error error
TxValidationCode pb.TxValidationCode
}

// ExecuteTxRequest contains the parameters to execute transaction
Expand Down
23 changes: 13 additions & 10 deletions pkg/fabric-txn/admin/transactionconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
internal "github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/internal"
"github.com/hyperledger/fabric-sdk-go/pkg/logging"
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/peer"
)

var logger = logging.NewLogger("fabric_sdk_go")
Expand Down Expand Up @@ -61,20 +62,21 @@ func SendInstantiateCC(channel fab.Channel, chainCodeID string, args []string,
}

// Register for commit event
done, fail := internal.RegisterTxEvent(txID, eventHub)
chcode := internal.RegisterTxEvent(txID, eventHub)

if _, err = internal.CreateAndSendTransaction(channel, transactionProposalResponse); err != nil {
return fmt.Errorf("CreateTransaction returned error: %v", err)
}

select {
case <-done:
case <-fail:
return fmt.Errorf("instantiateCC Error received from eventhub for txid(%s) error(%v)", txID, fail)
case code := <-chcode:
if code == peer.TxValidationCode_VALID {
return nil
}
return fmt.Errorf("instantiateCC Error received from eventhub for txid(%s), code(%s)", txID, code)
case <-time.After(time.Second * 30):
return fmt.Errorf("instantiateCC Didn't receive block event for txid(%s)", txID)
}
return nil
}

// SendUpgradeCC Sends upgrade CC proposal to one or more endorsing peers
Expand All @@ -95,20 +97,21 @@ func SendUpgradeCC(channel fab.Channel, chainCodeID string, args []string,
}

// Register for commit event
done, fail := internal.RegisterTxEvent(txID, eventHub)
chcode := internal.RegisterTxEvent(txID, eventHub)

if _, err = internal.CreateAndSendTransaction(channel, transactionProposalResponse); err != nil {
return fmt.Errorf("CreateTransaction returned error: %v", err)
}

select {
case <-done:
case <-fail:
return fmt.Errorf("upgradeCC Error received from eventhub for txid(%s) error(%v)", txID, fail)
case code := <-chcode:
if code == peer.TxValidationCode_VALID {
return nil
}
return fmt.Errorf("upgradeCC Error received from eventhub for txid(%s) code(%s)", txID, code)
case <-time.After(time.Second * 30):
return fmt.Errorf("upgradeCC Didn't receive block event for txid(%s)", txID)
}
return nil
}

// CreateOrUpdateChannel creates a channel if it does not exist or updates a channel
Expand Down
13 changes: 8 additions & 5 deletions pkg/fabric-txn/chclient/chclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/hyperledger/fabric-sdk-go/api/apitxn"
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/peer"
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/internal"
pb "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/peer"
)

const (
Expand Down Expand Up @@ -170,18 +171,20 @@ func sendTransaction(channel fab.Channel, txID apitxn.TransactionID, txProposalR
}
}

done, fail := internal.RegisterTxEvent(txID, eventHub)
chcode := internal.RegisterTxEvent(txID, eventHub)
_, err := internal.CreateAndSendTransaction(channel, txProposalResponses)
if err != nil {
notifier <- apitxn.ExecuteTxResponse{Response: apitxn.TransactionID{}, Error: fmt.Errorf("CreateAndSendTransaction returned error: %v", err)}
return
}

select {
case <-done:
notifier <- apitxn.ExecuteTxResponse{Response: txID, Error: nil}
case err := <-fail:
notifier <- apitxn.ExecuteTxResponse{Response: txID, Error: fmt.Errorf("ExecuteTx received an error from eventhub for txid(%s), error(%v)", txID, err)}
case code := <-chcode:
if code == pb.TxValidationCode_VALID {
notifier <- apitxn.ExecuteTxResponse{Response: txID, TxValidationCode: code}
} else {
notifier <- apitxn.ExecuteTxResponse{Response: txID, TxValidationCode: code, Error: fmt.Errorf("ExecuteTx received a failed transaction response from eventhub for txid(%s), code(%s)", txID, code)}
}
case <-time.After(timeout):
notifier <- apitxn.ExecuteTxResponse{Response: txID, Error: fmt.Errorf("ExecuteTx didn't receive block event for txid(%s)", txID)}
}
Expand Down
26 changes: 11 additions & 15 deletions pkg/fabric-txn/internal/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,17 @@ func CreateAndSendTransaction(sender apitxn.Sender, resps []*apitxn.TransactionP
}

// RegisterTxEvent registers on the given eventhub for the given transaction id
// returns a boolean channel which receives true when the event is complete and
// an error channel for errors
func RegisterTxEvent(txID apitxn.TransactionID, eventHub fab.EventHub) (chan bool, chan error) {
done := make(chan bool)
fail := make(chan error)

eventHub.RegisterTxEvent(txID, func(txId string, errorCode pb.TxValidationCode, err error) {
if err != nil {
logger.Debugf("Received error event for txid(%s)\n", txId)
fail <- err
} else {
logger.Debugf("Received success event for txid(%s)\n", txId)
done <- true
}
// returns a TxValidationCode channel which receives the validation code when the
// transaction completes. If the code is TxValidationCode_VALID then
// the transaction committed successfully, otherwise the code indicates the error
// that occurred.
func RegisterTxEvent(txID apitxn.TransactionID, eventHub fab.EventHub) chan pb.TxValidationCode {
chcode := make(chan pb.TxValidationCode)

eventHub.RegisterTxEvent(txID, func(txId string, code pb.TxValidationCode, err error) {
logger.Debugf("Received code(%s) for txid(%s)\n", code, txId)
chcode <- code
})

return done, fail
return chcode
}
13 changes: 7 additions & 6 deletions pkg/fabric-txn/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
"github.com/hyperledger/fabric-sdk-go/api/apitxn"
internal "github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/internal"
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/peer"

"github.com/hyperledger/fabric-sdk-go/pkg/logging"
)
Expand Down Expand Up @@ -68,22 +69,22 @@ func InvokeChaincode(client fab.FabricClient, channel fab.Channel, targets []api
return apitxn.TransactionID{}, fmt.Errorf("CreateAndSendTransactionProposal returned error: %v", err)
}

done, fail := internal.RegisterTxEvent(txID, eventHub)
chcode := internal.RegisterTxEvent(txID, eventHub)

_, err = internal.CreateAndSendTransaction(channel, transactionProposalResponses)
if err != nil {
return txID, fmt.Errorf("CreateAndSendTransaction returned error: %v", err)
}

select {
case <-done:
case err := <-fail:
return txID, fmt.Errorf("invoke Error received from eventhub for txid(%s), error(%v)", txID, err)
case code := <-chcode:
if code == peer.TxValidationCode_VALID {
return txID, nil
}
return txID, fmt.Errorf("invoke Error received from eventhub for txid(%s), code(%s)", txID, code)
case <-time.After(time.Second * 30):
return txID, fmt.Errorf("invoke Didn't receive block event for txid(%s)", txID)
}

return txID, nil
}

// checkCommonArgs ...
Expand Down
4 changes: 4 additions & 0 deletions test/integration/channel_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/hyperledger/fabric-sdk-go/api/apitxn"
"github.com/hyperledger/fabric-sdk-go/def/fabapi"
"github.com/hyperledger/fabric-sdk-go/def/fabapi/opt"
pb "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/peer"
)

var queryArgs = [][]byte{[]byte("query"), []byte("b")}
Expand Down Expand Up @@ -149,6 +150,9 @@ func testAsyncTransaction(ccID string, chClient apitxn.ChannelClient, t *testing
if response.Error != nil {
t.Fatalf("ExecuteTx returned error: %s", response.Error)
}
if response.TxValidationCode != pb.TxValidationCode_VALID {
t.Fatalf("Expecting TxValidationCode to be TxValidationCode_VALID but received: %s", response.TxValidationCode)
}
case <-time.After(time.Second * 20):
t.Fatalf("ExecuteTx timed out")
}
Expand Down

0 comments on commit 2578687

Please sign in to comment.