Skip to content

Commit

Permalink
[FAB-8968] Ledger Client: QueryBlockByTxID
Browse files Browse the repository at this point in the history
Change-Id: I197c3187dcc47b16684f0335930afba5c4810bd0
Signed-off-by: Sandra Vrtikapa <[email protected]>
  • Loading branch information
sandrask committed Mar 19, 2018
1 parent e131b61 commit 9a32e55
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 2 deletions.
43 changes: 43 additions & 0 deletions pkg/client/ledger/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,49 @@ func (c *Client) QueryBlockByHash(blockHash []byte, options ...RequestOption) (*
return response, err
}

// QueryBlockByTxID returns a block which contains a transaction
// This query will be made to specified targets.
// Returns the block.
func (c *Client) QueryBlockByTxID(txID fab.TransactionID, options ...RequestOption) (*common.Block, error) {

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

// Determine targets
targets, err := c.calculateTargets(opts)
if err != nil {
return nil, errors.WithMessage(err, "failed to determine target peers for QueryBlockByTxID")
}

reqCtx, cancel := c.createRequestContext(&opts)
defer cancel()

responses, err := c.ledger.QueryBlockByTxID(reqCtx, txID, peersToTxnProcessors(targets), c.verifier)
if err != nil && len(responses) == 0 {
return nil, errors.WithMessage(err, "Failed to QueryBlockByTxID")
}

if len(responses) < opts.MinTargets {
return nil, errors.Errorf("QueryBlockByTxID: Number of responses %d is less than MinTargets %d", len(responses), opts.MinTargets)
}

response := responses[0]
for i, r := range responses {
if i == 0 {
continue
}

// All payloads have to match
if !proto.Equal(response.Data, r.Data) {
return nil, errors.New("Payloads for QueryBlockByTxID do not match")
}
}

return response, err
}

// QueryBlock queries the ledger for Block by block number.
// This query will be made to specified targets.
// blockNumber: The number which is the ID of the Block.
Expand Down
18 changes: 18 additions & 0 deletions pkg/fab/channel/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,24 @@ func (c *Ledger) QueryBlockByHash(reqCtx reqContext.Context, blockHash []byte, t
return responses, errs
}

// QueryBlockByTxID returns a block which contains a transaction
// This query will be made to specified targets.
// Returns the block.
func (c *Ledger) QueryBlockByTxID(reqCtx reqContext.Context, txID fab.TransactionID, targets []fab.ProposalProcessor, verifier ResponseVerifier) ([]*common.Block, error) {

if txID == "" {
return nil, errors.New("txID is required")
}

cir := createBlockByTxIDInvokeRequest(c.chName, txID)
tprs, errs := queryChaincode(reqCtx, c.chName, cir, targets, verifier)

responses, errors := getConfigBlocks(tprs)
errs = multi.Append(errs, errors)

return responses, errs
}

func getConfigBlocks(tprs []*fab.TransactionProposalResponse) ([]*common.Block, error) {
responses := []*common.Block{}
var errs error
Expand Down
13 changes: 11 additions & 2 deletions pkg/fab/channel/ledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package channel
import (
"errors"
"fmt"
"strings"
"testing"

"time"
Expand Down Expand Up @@ -51,6 +52,11 @@ func TestQueryMethods(t *testing.T) {
if err == nil {
t.Fatalf("Query hash cannot be nil")
}

_, err = channel.QueryBlockByTxID(reqCtx, "", []fab.ProposalProcessor{&peer}, nil)
if err == nil || !strings.Contains(err.Error(), "txID is required") {
t.Fatalf("Tx ID cannot be nil")
}
}

func TestChannelQueryBlock(t *testing.T) {
Expand All @@ -62,15 +68,18 @@ func TestChannelQueryBlock(t *testing.T) {
defer cancel()

_, err := channel.QueryBlock(reqCtx, 1, []fab.ProposalProcessor{&peer}, nil)

if err != nil {
t.Fatalf("Test channel query block failed: %s", err)
}

_, err = channel.QueryBlockByHash(reqCtx, []byte(""), []fab.ProposalProcessor{&peer}, nil)
if err != nil {
t.Fatalf("Test channel query block by hash failed: %s", err)
}

_, err = channel.QueryBlockByTxID(reqCtx, "1234", []fab.ProposalProcessor{&peer}, nil)
if err != nil {
t.Fatal("Test channel query block by hash failed,")
t.Fatalf("Test channel query block by tx ID failed: %s", err)
}

}
Expand Down
14 changes: 14 additions & 0 deletions pkg/fab/channel/qscc.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const (
qsccChannelInfo = "GetChainInfo"
qsccBlockByHash = "GetBlockByHash"
qsccBlockByNumber = "GetBlockByNumber"
qsccBlockByTxID = "GetBlockByTxID"
)

func createTransactionByIDInvokeRequest(channelID string, transactionID fab.TransactionID) fab.ChaincodeInvokeRequest {
Expand Down Expand Up @@ -72,3 +73,16 @@ func createBlockByNumberInvokeRequest(channelID string, blockNumber uint64) fab.
}
return cir
}

func createBlockByTxIDInvokeRequest(channelID string, transactionID fab.TransactionID) fab.ChaincodeInvokeRequest {
var args [][]byte
args = append(args, []byte(channelID))
args = append(args, []byte(transactionID))

cir := fab.ChaincodeInvokeRequest{
ChaincodeID: qscc,
Fcn: qsccBlockByTxID,
Args: args,
}
return cir
}
21 changes: 21 additions & 0 deletions test/integration/fab/channel_ledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ func TestLedgerQueries(t *testing.T) {

testQueryBlock(t, ledgerClient, targets)

testQueryBlockByTxID(t, ledgerClient, txID, targets)

//prepare context
clientCtx := sdk.Context(fabsdk.WithUser("Admin"), fabsdk.WithOrg(orgName))

Expand Down Expand Up @@ -216,6 +218,25 @@ func testQueryBlock(t *testing.T, ledgerClient *ledger.Client, targets []string)
}
}

func testQueryBlockByTxID(t *testing.T, ledgerClient *ledger.Client, txID fab.TransactionID, targets []string) {

// Test Query Block- retrieve block by non-existent tx ID
_, err := ledgerClient.QueryBlockByTxID("non-existent", ledger.WithTargetURLs(targets...))
if err == nil {
t.Fatal("QueryBlockByTxID non-existent didn't return an error")
}

// Test Query Block - retrieve block by valid tx ID
block, err := ledgerClient.QueryBlockByTxID(txID, ledger.WithTargetURLs(targets...))
if err != nil {
t.Fatalf("QueryBlockByTxID return error: %v", err)
}
if block.Data == nil {
t.Fatal("QueryBlockByTxID block data is nil")
}

}

func testInstantiatedChaincodes(t *testing.T, ccID string, channelID string, resmgmtClient *resmgmt.Client, targets []string) {

found := false
Expand Down

0 comments on commit 9a32e55

Please sign in to comment.