@@ -34,6 +34,12 @@ type Ledger struct {
3434 chName string
3535}
3636
37+ // ResponseVerifier checks transaction proposal response(s)
38+ type ResponseVerifier interface {
39+ Verify (response * fab.TransactionProposalResponse ) error
40+ Match (response []* fab.TransactionProposalResponse ) error
41+ }
42+
3743// NewLedger constructs a Ledger client for the current context and named channel.
3844func NewLedger (chName string ) (* Ledger , error ) {
3945 l := Ledger {
@@ -44,11 +50,11 @@ func NewLedger(chName string) (*Ledger, error) {
4450
4551// QueryInfo queries for various useful information on the state of the channel
4652// (height, known peers).
47- func (c * Ledger ) QueryInfo (reqCtx reqContext.Context , targets []fab.ProposalProcessor ) ([]* fab.BlockchainInfoResponse , error ) {
53+ func (c * Ledger ) QueryInfo (reqCtx reqContext.Context , targets []fab.ProposalProcessor , verifier ResponseVerifier ) ([]* fab.BlockchainInfoResponse , error ) {
4854 logger .Debug ("queryInfo - start" )
4955
5056 cir := createChannelInfoInvokeRequest (c .chName )
51- tprs , errs := queryChaincode (reqCtx , c .chName , cir , targets )
57+ tprs , errs := queryChaincode (reqCtx , c .chName , cir , targets , verifier )
5258
5359 responses := []* fab.BlockchainInfoResponse {}
5460 for _ , tpr := range tprs {
@@ -74,14 +80,14 @@ func createBlockchainInfo(tpr *fab.TransactionProposalResponse) (*common.Blockch
7480// QueryBlockByHash queries the ledger for Block by block hash.
7581// This query will be made to specified targets.
7682// Returns the block.
77- func (c * Ledger ) QueryBlockByHash (reqCtx reqContext.Context , blockHash []byte , targets []fab.ProposalProcessor ) ([]* common.Block , error ) {
83+ func (c * Ledger ) QueryBlockByHash (reqCtx reqContext.Context , blockHash []byte , targets []fab.ProposalProcessor , verifier ResponseVerifier ) ([]* common.Block , error ) {
7884
7985 if blockHash == nil {
8086 return nil , errors .New ("blockHash is required" )
8187 }
8288
8389 cir := createBlockByHashInvokeRequest (c .chName , blockHash )
84- tprs , errs := queryChaincode (reqCtx , c .chName , cir , targets )
90+ tprs , errs := queryChaincode (reqCtx , c .chName , cir , targets , verifier )
8591
8692 responses := []* common.Block {}
8793 for _ , tpr := range tprs {
@@ -99,10 +105,10 @@ func (c *Ledger) QueryBlockByHash(reqCtx reqContext.Context, blockHash []byte, t
99105// This query will be made to specified targets.
100106// blockNumber: The number which is the ID of the Block.
101107// It returns the block.
102- func (c * Ledger ) QueryBlock (reqCtx reqContext.Context , blockNumber uint64 , targets []fab.ProposalProcessor ) ([]* common.Block , error ) {
108+ func (c * Ledger ) QueryBlock (reqCtx reqContext.Context , blockNumber uint64 , targets []fab.ProposalProcessor , verifier ResponseVerifier ) ([]* common.Block , error ) {
103109
104110 cir := createBlockByNumberInvokeRequest (c .chName , blockNumber )
105- tprs , errs := queryChaincode (reqCtx , c .chName , cir , targets )
111+ tprs , errs := queryChaincode (reqCtx , c .chName , cir , targets , verifier )
106112
107113 responses := []* common.Block {}
108114 for _ , tpr := range tprs {
@@ -128,10 +134,10 @@ func createCommonBlock(tpr *fab.TransactionProposalResponse) (*common.Block, err
128134// QueryTransaction queries the ledger for Transaction by number.
129135// This query will be made to specified targets.
130136// Returns the ProcessedTransaction information containing the transaction.
131- func (c * Ledger ) QueryTransaction (reqCtx reqContext.Context , transactionID fab.TransactionID , targets []fab.ProposalProcessor ) ([]* pb.ProcessedTransaction , error ) {
137+ func (c * Ledger ) QueryTransaction (reqCtx reqContext.Context , transactionID fab.TransactionID , targets []fab.ProposalProcessor , verifier ResponseVerifier ) ([]* pb.ProcessedTransaction , error ) {
132138
133139 cir := createTransactionByIDInvokeRequest (c .chName , transactionID )
134- tprs , errs := queryChaincode (reqCtx , c .chName , cir , targets )
140+ tprs , errs := queryChaincode (reqCtx , c .chName , cir , targets , verifier )
135141
136142 responses := []* pb.ProcessedTransaction {}
137143 for _ , tpr := range tprs {
@@ -157,9 +163,9 @@ func createProcessedTransaction(tpr *fab.TransactionProposalResponse) (*pb.Proce
157163
158164// QueryInstantiatedChaincodes queries the instantiated chaincodes on this channel.
159165// This query will be made to specified targets.
160- func (c * Ledger ) QueryInstantiatedChaincodes (reqCtx reqContext.Context , targets []fab.ProposalProcessor ) ([]* pb.ChaincodeQueryResponse , error ) {
166+ func (c * Ledger ) QueryInstantiatedChaincodes (reqCtx reqContext.Context , targets []fab.ProposalProcessor , verifier ResponseVerifier ) ([]* pb.ChaincodeQueryResponse , error ) {
161167 cir := createChaincodeInvokeRequest ()
162- tprs , errs := queryChaincode (reqCtx , c .chName , cir , targets )
168+ tprs , errs := queryChaincode (reqCtx , c .chName , cir , targets , verifier )
163169
164170 responses := []* pb.ChaincodeQueryResponse {}
165171 for _ , tpr := range tprs {
@@ -184,7 +190,7 @@ func createChaincodeQueryResponse(tpr *fab.TransactionProposalResponse) (*pb.Cha
184190
185191// QueryConfigBlock returns the current configuration block for the specified channel. If the
186192// peer doesn't belong to the channel, return error
187- func (c * Ledger ) QueryConfigBlock (reqCtx reqContext.Context , targets []fab.ProposalProcessor , minResponses int ) (* common.ConfigEnvelope , error ) {
193+ func (c * Ledger ) QueryConfigBlock (reqCtx reqContext.Context , targets []fab.ProposalProcessor , minResponses int , verifier ResponseVerifier ) (* common.ConfigEnvelope , error ) {
188194
189195 if len (targets ) == 0 {
190196 return nil , errors .New ("target(s) required" )
@@ -195,7 +201,7 @@ func (c *Ledger) QueryConfigBlock(reqCtx reqContext.Context, targets []fab.Propo
195201 }
196202
197203 cir := createConfigBlockInvokeRequest (c .chName )
198- tprs , err := queryChaincode (reqCtx , c .chName , cir , targets )
204+ tprs , err := queryChaincode (reqCtx , c .chName , cir , targets , verifier )
199205 if err != nil && len (tprs ) == 0 {
200206 return nil , errors .WithMessage (err , "queryChaincode failed" )
201207 }
@@ -242,7 +248,7 @@ func collectProposalResponses(tprs []*fab.TransactionProposalResponse) [][]byte
242248 return responses
243249}
244250
245- func queryChaincode (reqCtx reqContext.Context , channelID string , request fab.ChaincodeInvokeRequest , targets []fab.ProposalProcessor ) ([]* fab.TransactionProposalResponse , error ) {
251+ func queryChaincode (reqCtx reqContext.Context , channelID string , request fab.ChaincodeInvokeRequest , targets []fab.ProposalProcessor , verifier ResponseVerifier ) ([]* fab.TransactionProposalResponse , error ) {
246252 ctx , ok := contextImpl .RequestClientContext (reqCtx )
247253 if ! ok {
248254 return nil , errors .New ("failed get client context from reqContext for signProposal" )
@@ -258,13 +264,19 @@ func queryChaincode(reqCtx reqContext.Context, channelID string, request fab.Cha
258264 }
259265 tprs , errs := txn .SendProposal (reqCtx , tp , targets )
260266
261- return filterResponses (tprs , errs )
267+ return filterResponses (tprs , errs , verifier )
262268}
263269
264- func filterResponses (responses []* fab.TransactionProposalResponse , errs error ) ([]* fab.TransactionProposalResponse , error ) {
270+ func filterResponses (responses []* fab.TransactionProposalResponse , errs error , verifier ResponseVerifier ) ([]* fab.TransactionProposalResponse , error ) {
265271 filteredResponses := responses [:0 ]
266272 for _ , response := range responses {
267273 if response .Status == http .StatusOK {
274+ if verifier != nil {
275+ if err := verifier .Verify (response ); err != nil {
276+ errs = multi .Append (errs , errors .Errorf ("failed to verify response from %s: %s" , response .Endorser , err ))
277+ continue
278+ }
279+ }
268280 filteredResponses = append (filteredResponses , response )
269281 } else {
270282 errs = multi .Append (errs , errors .Errorf ("bad status from %s (%d)" , response .Endorser , response .Status ))
0 commit comments