github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/scc/qscc/query.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package qscc
    18  
    19  import (
    20  	"fmt"
    21  	"strconv"
    22  
    23  	"github.com/hyperledger/fabric/common/flogging"
    24  	"github.com/op/go-logging"
    25  
    26  	"github.com/hyperledger/fabric/common/policies"
    27  	"github.com/hyperledger/fabric/core/chaincode/shim"
    28  	"github.com/hyperledger/fabric/core/ledger"
    29  	"github.com/hyperledger/fabric/core/peer"
    30  	"github.com/hyperledger/fabric/core/policy"
    31  	"github.com/hyperledger/fabric/msp/mgmt"
    32  	pb "github.com/hyperledger/fabric/protos/peer"
    33  	"github.com/hyperledger/fabric/protos/utils"
    34  )
    35  
    36  // LedgerQuerier implements the ledger query functions, including:
    37  // - GetChainInfo returns BlockchainInfo
    38  // - GetBlockByNumber returns a block
    39  // - GetBlockByHash returns a block
    40  // - GetTransactionByID returns a transaction
    41  type LedgerQuerier struct {
    42  	policyChecker policy.PolicyChecker
    43  }
    44  
    45  var qscclogger = flogging.MustGetLogger("qscc")
    46  
    47  // These are function names from Invoke first parameter
    48  const (
    49  	GetChainInfo       string = "GetChainInfo"
    50  	GetBlockByNumber   string = "GetBlockByNumber"
    51  	GetBlockByHash     string = "GetBlockByHash"
    52  	GetTransactionByID string = "GetTransactionByID"
    53  	GetBlockByTxID     string = "GetBlockByTxID"
    54  )
    55  
    56  // Init is called once per chain when the chain is created.
    57  // This allows the chaincode to initialize any variables on the ledger prior
    58  // to any transaction execution on the chain.
    59  func (e *LedgerQuerier) Init(stub shim.ChaincodeStubInterface) pb.Response {
    60  	qscclogger.Info("Init QSCC")
    61  
    62  	// Init policy checker for access control
    63  	e.policyChecker = policy.NewPolicyChecker(
    64  		peer.NewChannelPolicyManagerGetter(),
    65  		mgmt.GetLocalMSP(),
    66  		mgmt.NewLocalMSPPrincipalGetter(),
    67  	)
    68  
    69  	return shim.Success(nil)
    70  }
    71  
    72  // Invoke is called with args[0] contains the query function name, args[1]
    73  // contains the chain ID, which is temporary for now until it is part of stub.
    74  // Each function requires additional parameters as described below:
    75  // # GetChainInfo: Return a BlockchainInfo object marshalled in bytes
    76  // # GetBlockByNumber: Return the block specified by block number in args[2]
    77  // # GetBlockByHash: Return the block specified by block hash in args[2]
    78  // # GetTransactionByID: Return the transaction specified by ID in args[2]
    79  func (e *LedgerQuerier) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    80  	args := stub.GetArgs()
    81  
    82  	if len(args) < 2 {
    83  		return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args)))
    84  	}
    85  	fname := string(args[0])
    86  	cid := string(args[1])
    87  
    88  	if fname != GetChainInfo && len(args) < 3 {
    89  		return shim.Error(fmt.Sprintf("missing 3rd argument for %s", fname))
    90  	}
    91  
    92  	targetLedger := peer.GetLedger(cid)
    93  	if targetLedger == nil {
    94  		return shim.Error(fmt.Sprintf("Invalid chain ID, %s", cid))
    95  	}
    96  	if qscclogger.IsEnabledFor(logging.DEBUG) {
    97  		qscclogger.Debugf("Invoke function: %s on chain: %s", fname, cid)
    98  	}
    99  
   100  	// Handle ACL:
   101  	// 1. get the signed proposal
   102  	sp, err := stub.GetSignedProposal()
   103  	if err != nil {
   104  		return shim.Error(fmt.Sprintf("Failed getting signed proposal from stub, %s: %s", cid, err))
   105  	}
   106  
   107  	// 2. check the channel reader policy
   108  	if err = e.policyChecker.CheckPolicy(cid, policies.ChannelApplicationReaders, sp); err != nil {
   109  		return shim.Error(fmt.Sprintf("Authorization request failed %s: %s", cid, err))
   110  	}
   111  
   112  	switch fname {
   113  	case GetTransactionByID:
   114  		return getTransactionByID(targetLedger, args[2])
   115  	case GetBlockByNumber:
   116  		return getBlockByNumber(targetLedger, args[2])
   117  	case GetBlockByHash:
   118  		return getBlockByHash(targetLedger, args[2])
   119  	case GetChainInfo:
   120  		return getChainInfo(targetLedger)
   121  	case GetBlockByTxID:
   122  		return getBlockByTxID(targetLedger, args[2])
   123  	}
   124  
   125  	return shim.Error(fmt.Sprintf("Requested function %s not found.", fname))
   126  }
   127  
   128  func getTransactionByID(vledger ledger.PeerLedger, tid []byte) pb.Response {
   129  	if tid == nil {
   130  		return shim.Error("Transaction ID must not be nil.")
   131  	}
   132  
   133  	processedTran, err := vledger.GetTransactionByID(string(tid))
   134  	if err != nil {
   135  		return shim.Error(fmt.Sprintf("Failed to get transaction with id %s, error %s", string(tid), err))
   136  	}
   137  
   138  	bytes, err := utils.Marshal(processedTran)
   139  	if err != nil {
   140  		return shim.Error(err.Error())
   141  	}
   142  
   143  	return shim.Success(bytes)
   144  }
   145  
   146  func getBlockByNumber(vledger ledger.PeerLedger, number []byte) pb.Response {
   147  	if number == nil {
   148  		return shim.Error("Block number must not be nil.")
   149  	}
   150  	bnum, err := strconv.ParseUint(string(number), 10, 64)
   151  	if err != nil {
   152  		return shim.Error(fmt.Sprintf("Failed to parse block number with error %s", err))
   153  	}
   154  	block, err := vledger.GetBlockByNumber(bnum)
   155  	if err != nil {
   156  		return shim.Error(fmt.Sprintf("Failed to get block number %d, error %s", bnum, err))
   157  	}
   158  	// TODO: consider trim block content before returning
   159  	//  Specifically, trim transaction 'data' out of the transaction array Payloads
   160  	//  This will preserve the transaction Payload header,
   161  	//  and client can do GetTransactionByID() if they want the full transaction details
   162  
   163  	bytes, err := utils.Marshal(block)
   164  	if err != nil {
   165  		return shim.Error(err.Error())
   166  	}
   167  
   168  	return shim.Success(bytes)
   169  }
   170  
   171  func getBlockByHash(vledger ledger.PeerLedger, hash []byte) pb.Response {
   172  	if hash == nil {
   173  		return shim.Error("Block hash must not be nil.")
   174  	}
   175  	block, err := vledger.GetBlockByHash(hash)
   176  	if err != nil {
   177  		return shim.Error(fmt.Sprintf("Failed to get block hash %s, error %s", string(hash), err))
   178  	}
   179  	// TODO: consider trim block content before returning
   180  	//  Specifically, trim transaction 'data' out of the transaction array Payloads
   181  	//  This will preserve the transaction Payload header,
   182  	//  and client can do GetTransactionByID() if they want the full transaction details
   183  
   184  	bytes, err := utils.Marshal(block)
   185  	if err != nil {
   186  		return shim.Error(err.Error())
   187  	}
   188  
   189  	return shim.Success(bytes)
   190  }
   191  
   192  func getChainInfo(vledger ledger.PeerLedger) pb.Response {
   193  	binfo, err := vledger.GetBlockchainInfo()
   194  	if err != nil {
   195  		return shim.Error(fmt.Sprintf("Failed to get block info with error %s", err))
   196  	}
   197  	bytes, err := utils.Marshal(binfo)
   198  	if err != nil {
   199  		return shim.Error(err.Error())
   200  	}
   201  
   202  	return shim.Success(bytes)
   203  }
   204  
   205  func getBlockByTxID(vledger ledger.PeerLedger, rawTxID []byte) pb.Response {
   206  	txID := string(rawTxID)
   207  	block, err := vledger.GetBlockByTxID(txID)
   208  
   209  	if err != nil {
   210  		return shim.Error(fmt.Sprintf("Failed to get block for txID %s, error %s", txID, err))
   211  	}
   212  
   213  	bytes, err := utils.Marshal(block)
   214  
   215  	if err != nil {
   216  		return shim.Error(err.Error())
   217  	}
   218  
   219  	return shim.Success(bytes)
   220  }