Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Commit bc269e6

Browse files
committed
[FAB-8191] Split ledger queries from channel
This patch creates a new ChannelLedger type that contains query methods to a channel's underlying ledger. Change-Id: Ie94e04b6139075af6462d239c47689d18e1bca59 Signed-off-by: Troy Ronda <troy@troyronda.com>
1 parent f2b1c3b commit bc269e6

File tree

9 files changed

+601
-452
lines changed

9 files changed

+601
-452
lines changed

api/apifabclient/channel.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ type Channel interface {
5959
QueryConfigBlock(peers []Peer, minResponses int) (*common.ConfigEnvelope, error)
6060
}
6161

62+
// ChannelLedger provides access to the underlying ledger for a channel.
63+
type ChannelLedger interface {
64+
QueryInfo(targets []ProposalProcessor) (*common.BlockchainInfo, error)
65+
QueryBlock(blockNumber int, targets []ProposalProcessor) (*common.Block, error)
66+
QueryBlockByHash(blockHash []byte, targets []ProposalProcessor) (*common.Block, error)
67+
QueryTransaction(transactionID string, targets []ProposalProcessor) (*pb.ProcessedTransaction, error)
68+
QueryInstantiatedChaincodes(targets []ProposalProcessor) (*pb.ChaincodeQueryResponse, error)
69+
}
70+
6271
// OrgAnchorPeer contains information about an anchor peer on this channel
6372
type OrgAnchorPeer struct {
6473
Org string

pkg/fabric-client/channel/channel.go

Lines changed: 100 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,20 @@ SPDX-License-Identifier: Apache-2.0
77
package channel
88

99
import (
10-
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
11-
1210
"crypto/x509"
13-
1411
"encoding/pem"
15-
12+
"regexp"
1613
"strings"
1714

18-
"regexp"
15+
"github.com/pkg/errors"
1916

2017
"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
18+
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
2119
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/msp"
2220
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/orderer"
2321
"github.com/hyperledger/fabric-sdk-go/pkg/logging"
24-
"github.com/pkg/errors"
22+
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/common"
23+
pb "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/peer"
2524
)
2625

2726
var logger = logging.NewLogger("fabric_sdk_go")
@@ -327,3 +326,98 @@ func resolveOrdererURL(ordererURL string) string {
327326
}
328327
return "grpcs://" + ordererURL
329328
}
329+
330+
// QueryInfo queries for various useful information on the state of the channel
331+
// (height, known peers).
332+
// This query will be made to the primary peer.
333+
func (c *Channel) QueryInfo() (*common.BlockchainInfo, error) {
334+
l := NewLedger(c.clientContext, c.name)
335+
resps, err := l.QueryInfo([]fab.ProposalProcessor{c.PrimaryPeer()})
336+
if err != nil {
337+
return nil, err
338+
}
339+
return resps[0], err
340+
}
341+
342+
// QueryBlockByHash queries the ledger for Block by block hash.
343+
// This query will be made to the primary peer.
344+
// Returns the block.
345+
func (c *Channel) QueryBlockByHash(blockHash []byte) (*common.Block, error) {
346+
l := NewLedger(c.clientContext, c.name)
347+
resps, err := l.QueryBlockByHash(blockHash, []fab.ProposalProcessor{c.PrimaryPeer()})
348+
if err != nil {
349+
return nil, err
350+
}
351+
return resps[0], err
352+
}
353+
354+
// QueryBlock queries the ledger for Block by block number.
355+
// This query will be made to the primary peer.
356+
// blockNumber: The number which is the ID of the Block.
357+
// It returns the block.
358+
func (c *Channel) QueryBlock(blockNumber int) (*common.Block, error) {
359+
l := NewLedger(c.clientContext, c.name)
360+
resps, err := l.QueryBlock(blockNumber, []fab.ProposalProcessor{c.PrimaryPeer()})
361+
if err != nil {
362+
return nil, err
363+
}
364+
return resps[0], err
365+
}
366+
367+
// QueryTransaction queries the ledger for Transaction by number.
368+
// This query will be made to the primary peer.
369+
// Returns the ProcessedTransaction information containing the transaction.
370+
// TODO: add optional target
371+
func (c *Channel) QueryTransaction(transactionID string) (*pb.ProcessedTransaction, error) {
372+
l := NewLedger(c.clientContext, c.name)
373+
resps, err := l.QueryTransaction(transactionID, []fab.ProposalProcessor{c.PrimaryPeer()})
374+
if err != nil {
375+
return nil, err
376+
}
377+
return resps[0], err
378+
}
379+
380+
// QueryInstantiatedChaincodes queries the instantiated chaincodes on this channel.
381+
// This query will be made to the primary peer.
382+
func (c *Channel) QueryInstantiatedChaincodes() (*pb.ChaincodeQueryResponse, error) {
383+
l := NewLedger(c.clientContext, c.name)
384+
resps, err := l.QueryInstantiatedChaincodes([]fab.ProposalProcessor{c.PrimaryPeer()})
385+
if err != nil {
386+
return nil, err
387+
}
388+
return resps[0], err
389+
390+
}
391+
392+
// QueryConfigBlock returns the current configuration block for the specified channel. If the
393+
// peer doesn't belong to the channel, return error
394+
func (c *Channel) QueryConfigBlock(peers []fab.Peer, minResponses int) (*common.ConfigEnvelope, error) {
395+
l := NewLedger(c.clientContext, c.name)
396+
return l.QueryConfigBlock(peers, minResponses)
397+
}
398+
399+
// QueryByChaincode sends a proposal to one or more endorsing peers that will be handled by the chaincode.
400+
// This request will be presented to the chaincode 'invoke' and must understand
401+
// from the arguments that this is a query request. The chaincode must also return
402+
// results in the byte array format and the caller will have to be able to decode.
403+
// these results.
404+
func (c *Channel) QueryByChaincode(request fab.ChaincodeInvokeRequest) ([][]byte, error) {
405+
targets, err := c.chaincodeInvokeRequestAddDefaultPeers(request.Targets)
406+
if err != nil {
407+
return nil, err
408+
}
409+
resps, err := queryChaincode(c.clientContext, c.name, request, targets)
410+
return filterProposalResponses(resps, err)
411+
}
412+
413+
// QueryBySystemChaincode invokes a chaincode that isn't part of a channel.
414+
//
415+
// TODO: This function's name is confusing - call the normal QueryByChaincode for system chaincode on a channel.
416+
func (c *Channel) QueryBySystemChaincode(request fab.ChaincodeInvokeRequest) ([][]byte, error) {
417+
targets, err := c.chaincodeInvokeRequestAddDefaultPeers(request.Targets)
418+
if err != nil {
419+
return nil, err
420+
}
421+
resps, err := queryChaincode(c.clientContext, systemChannel, request, targets)
422+
return filterProposalResponses(resps, err)
423+
}

pkg/fabric-client/channel/channel_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package channel
77

88
import (
99
"fmt"
10+
"reflect"
1011
"testing"
1112

1213
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
@@ -165,6 +166,45 @@ func TestPrimaryPeer(t *testing.T) {
165166

166167
}
167168

169+
func TestQueryOnSystemChannel(t *testing.T) {
170+
channel, _ := setupChannel(systemChannel)
171+
peer := mocks.MockPeer{MockName: "Peer1", MockURL: "http://peer1.com", MockRoles: []string{}, MockCert: nil, Status: 200}
172+
err := channel.AddPeer(&peer)
173+
if err != nil {
174+
t.Fatalf("Error adding peer to channel: %s", err)
175+
}
176+
177+
request := fab.ChaincodeInvokeRequest{
178+
ChaincodeID: "ccID",
179+
Fcn: "method",
180+
Args: [][]byte{[]byte("arg")},
181+
}
182+
if _, err := channel.QueryByChaincode(request); err != nil {
183+
t.Fatalf("Error invoking chaincode on system channel: %s", err)
184+
}
185+
}
186+
187+
func TestQueryBySystemChaincode(t *testing.T) {
188+
channel, _ := setupTestChannel()
189+
190+
peer := mocks.MockPeer{MockName: "Peer1", MockURL: "http://peer1.com", MockRoles: []string{}, MockCert: nil, Payload: []byte("A"), Status: 200}
191+
channel.AddPeer(&peer)
192+
193+
request := fab.ChaincodeInvokeRequest{
194+
ChaincodeID: "cc",
195+
Fcn: "Hello",
196+
}
197+
resp, err := channel.QueryBySystemChaincode(request)
198+
if err != nil {
199+
t.Fatalf("Failed to query: %s", err)
200+
}
201+
expectedResp := []byte("A")
202+
203+
if !reflect.DeepEqual(resp[0], expectedResp) {
204+
t.Fatalf("Unexpected transaction proposal response: %v", resp)
205+
}
206+
}
207+
168208
func isValueInList(value string, list []string) bool {
169209
for _, v := range list {
170210
if v == value {

0 commit comments

Comments
 (0)